Allow ViewExpression use session user explicitly#16436
Allow ViewExpression use session user explicitly#16436kokosing merged 4 commits intotrinodb:masterfrom
Conversation
ksobolew
left a comment
There was a problem hiding this comment.
It needs some additional test cases. But yeah, I like it (I worked in this area before, and it fixes one significant pain point).
core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java
Outdated
Show resolved
Hide resolved
core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java
Outdated
Show resolved
Hide resolved
core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java
Outdated
Show resolved
Hide resolved
core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java
Outdated
Show resolved
Hide resolved
|
Also, and I will repeat it again, ideally the |
|
This is also an SPI break. Just wanted to note this :) |
6bb2403 to
20b1128
Compare
Addressed. |
There was a problem hiding this comment.
Hm. I requested a test for this, but now I realize that it's actually difficult to test. The error message here (I think?) comes from the regular check if the SELECT has access to the columns, not from the check if the expression in the filter has access to them. A more proper test would require that the Identity of the current session has some additional attributes (like roles or groups) that grant it access, but an Identity with just the user does not. In such a case, previously the check for SELECT would be done for the former, which would pass, and the check for the mask expression would be done using the latter, which would fail. After this change the former would be reused for the latter, so both would pass.
There was a problem hiding this comment.
Added tests to TestAccessControl
findepi
left a comment
There was a problem hiding this comment.
"Remove obselete backward compability SPI exceptions"
core/trino-spi/pom.xml
Outdated
There was a problem hiding this comment.
above (<old>method void io.airlift.slice.SliceOutput::write(byte[]) throws java.io.IOException</old>) can also be removed
There was a problem hiding this comment.
That is not maven said. I removed that and then I had to restore it.
findepi
left a comment
There was a problem hiding this comment.
"Convert classes to records" LGTM
There was a problem hiding this comment.
What does "with user" mean? Did you mean "unprivileged user"?
"NotAccessible" -> "inaccessible"
There was a problem hiding this comment.
unprivileged user. I changed them again. Hopefully now is better.
findepi
left a comment
There was a problem hiding this comment.
"Introduce @internal SPI annotation"
There was a problem hiding this comment.
I generally like the idea of being able to say which "direction" does given class work.
How would we enforce our connectors do not call internal APIs?
How should external connectors' maintainers to that?
In this particular case, what if one connector needs, for some reason, to rewrap a ViewExpression returned by some other connector. Can it do that? Is it illegal?
There was a problem hiding this comment.
https://github.com/starburstdata/error-prone-checks can be a rescue.
Anyway I am removing this commit as it not the point of this PR and it requires its own discussion.
findepi
left a comment
There was a problem hiding this comment.
"Allow ViewExpression use session user explicitly" LGTM
would it be possible to make the change simpler?
For example, in StatamentAnalyzer have a logic conditional on session user equals view Expression's identity?
There was a problem hiding this comment.
Sometimes we have to introduce breaking changes.
So far we haven't been ultra strict about that, so I think it's fine to just change this method and add exclusion to revapi check. Let's defer intro of @Internal until we have more clairty what we want to achieve.
There was a problem hiding this comment.
Sometimes we have to introduce breaking changes.
I added a new method instead. I think we can avoid breaking change here. It is not a big deal.
There was a problem hiding this comment.
NotAccessible -> Inaccessible
"RowFilterAsInvoker" -- what does this mean?
do we have RUN AS INVOKER and RUN AS DEFINER row filers?
There was a problem hiding this comment.
do we have RUN AS INVOKER and RUN AS DEFINER row filers?
Not at the moment, but we're trying to introduce that, basically. The general idea is that column masks and row filters are view-like constructs, which should behave similarly to views. Views have the SECURITY clause, and with filters and masks the equivalent is the ViewExpression::identity. Currently access controls are forced to always provide this identity, which is as if all views were SECURITY DEFINER and the owner was the current session's user. Making this Optional is effectively adding SECURITY INVOKER to filters and masks. Though it could probably be named differently.
There was a problem hiding this comment.
"RowFilterAsInvoker" -- what does this mean?
I changed this to RunFilterAsSessionUser.
NotAccessible -> Inaccessible
The entire file is using NotAccessible. I will change that.
There was a problem hiding this comment.
Not at the moment, but we're trying to introduce that, basically.
Can we make the PR title convey that?
At first this looked like an optimization -- if filter owner is dumbly filled with session user, skip re-getting groups.
There was a problem hiding this comment.
Can we make the PR title convey that?
I was under impression it already does convey that. See Allow ViewExpression use session user explicitly where using session user is basically what SECURITY INVOKER is for views.
There was a problem hiding this comment.
You're right. It seems some things are obvious to you while they are not so obvious to me.
core/trino-main/src/test/java/io/trino/sql/query/TestFilterInaccessibleColumns.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
nice!
why tell the engine what the user is :)
There was a problem hiding this comment.
Yeah... engine knows it better.
There was a problem hiding this comment.
Can there be any difference between cases
- when ViewExpression has
emptyidentity - when ViewExpression has identity equal to current session user?
is it worth having a code comment why we don't check equality between them?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
20b1128 to
710e393
Compare
@dain Can you please elaborate? Please notice |
Before the change if access control is not returning any dedicated user to evaluate the view expression they just pass the session user. However for the engine it is not clear that is a session user and so engine needs to retrieve groups for that user again and possibly some session roles are lost. After this change access control may decide to return empty identity. That would be in line of view SECURITY INVOKER. Then engine can simply reuse the session identity.
710e393 to
16c3e44
Compare
I think we have been in this place with views where we had such condition. It has its own issues so that condition was removed from views. I don't want to introduce it for masks&filters. |
|
Does this need release notes? |
|
No. Thank you for asking. |
Allow ViewExpression use session user explicitly
Before the change if access control is not returning any dedicated user to evaluate
the view expression they just pass the session user. However for the
engine it is not clear that is a session user and so engine needs to
retrieve groups for that user again and possibly some session roles are
lost.
After this change access control may decide to return empty identity.
That would be in line of view SECURITY INVOKER. Then engine can simply
reuse the session identity.