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
Report failing access policy #4529
Conversation
For this schema:
This is how it displays the errors:
|
The codegen is getting complex, I don't know how to simplify it. This is generated SQL ...
"policy~1" AS MATERIALIZED (
(
SELECT
edgedb.raise_on_null(
nullif("expr-29~2"."expr~29_value~1", false),
'insufficient_privilege',
msg => 'access policy violation on insert of default::Movie (none of these allow policies match: __::insert_only_by_aljaz)',
"table" => 'cd33f102-4ee2-11ed-93f1-01441a342449'
) AS error_allow,
edgedb.raise_on_not_null(((
SELECT string_agg(error_msg, ', ')
FROM ((
SELECT 'denied by policy __::prevent_cats'
WHERE "expr-31~2"."expr~31_value~1"
) UNION (
SELECT 'denied by policy __::prevent_start_on_c'
WHERE "expr-35~2"."expr~35_value~1"
)) AS t(error_msg))),
'insufficient_privilege',
msg => (
'access policy violation on insert of default::Movie (' || (((
SELECT string_agg(error_msg, ', ')
FROM ((
SELECT 'denied by policy __::prevent_cats'
WHERE "expr-31~2"."expr~31_value~1"
) UNION (
SELECT 'denied by policy __::prevent_start_on_c'
WHERE "expr-35~2"."expr~35_value~1"
)) AS t(error_msg))
) || ')')
),
"table" => 'cd33f102-4ee2-11ed-93f1-01441a342449'
) AS error_deny
FROM
... |
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.
This is very solid looking, and it does a great job of handling pretty nasty requirements nicely.
I've got a hopefully final round of formatting nitpicks, though I'm also open to arguments about them :P
edb/pgsql/compiler/dml.py
Outdated
hint += ', '.join(allow_msgs) | ||
allow_msg = f'{msg} ({hint})' | ||
else: | ||
allow_msg = f'{msg} (no allow policies)' |
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.
I think I'd prefer to drop most of the extra helpful messages here, and just say access policy violation
and then, if applicable, following it, the relevant specified error messages.
My reasoning here is that the particular error might be sensitive information, and we don't want to give out any more than what the user asked to give. I'm willing to be convinced that this is not necessary, though.
I think it would be best to be able to produce error messages from both allow and deny rules at the same time, too?
The good news is I think all of these nitpicks should simplify the code, not make it more complex :P
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.
I agree, given that this is security it should not be verbose when denying access.
edb/pgsql/compiler/dml.py
Outdated
] | ||
deny_message = astutils.conditional_string_agg(deny_messages) | ||
if deny_message: | ||
deny_message = astutils.extend_concat( |
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.
Once the errmessage stuff is there, we'll need to handle the case where it errors but nothing with an error message failed
6e13c67
to
e374fa5
Compare
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.
Looks great!
edb/edgeql/compiler/policies.py
Outdated
@@ -39,6 +39,8 @@ | |||
from . import dispatch | |||
from . import setgen | |||
|
|||
T = TypeVar("T") |
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.
?
edb/edgeql/parser/grammar/sdl.py
Outdated
sdl_commands_block( | ||
'CreateAccessPolicy', | ||
SetAnnotation) | ||
sdl_commands_block('CreateAccessPolicy', SetField, SetAnnotation) |
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.
nit: Probably better to keep this expanded
As reference for later documentation (in #4943), I believe the algorithm is:
The rationale for this system is to avoid leaking any information that the developer did not opt-in to leak, in case the error messages are directly exposed to an end-user. Why a security policy failed is often sensitive information, so it needs to only be opt-in, and so we never do anything like just directly reporting policy names. |
Closes #4095
I have tests to do, but would ask for a quick peek if the major changes are ok.