Обсуждение: current_role of caller of a DEFINER function

Поиск
Список
Период
Сортировка

current_role of caller of a DEFINER function

От
Dominique Devienne
Дата:
Hi. I was led to believe (by an hallucination...) that I could know
the current_role of the caller of a DEFINER function, but after actual
experimentation, turns out it shows the OWNER of the function, and not
the current_role of the caller.

I foolishly thought curent_role != current_user inside the DEFINER
function, but reading back the doc, it's clear current_role =
current_user = user, thus that was wishful thinking. Only session_user
is representative of the caller, and reliable (modulo SUPERUSER and
SET AUTHORIZATION, but that's a different story and kinda normal)

So I have two questions:
1) Is there any way to know the current_role of the caller of a
DEFINER function. I fear the answer is no, but better be sure from
experts here.
2) Why isn't there a way to obtain the above? What harm would it be?

Obviously for #2, distinguishing current_role from current_user inside
DEFINER is a no-go, for backward compatibility. But could a new
variable be invented for that? What obvious technical reason I'm
missing would make that harmful or difficult?

As to the use-case, now that I have a queue mechanism for tasks to be
delegated to services, I need to make sure the poster of the task has
the right privileges, so I wanted to capture session_user and
current_role of the "poster", and the service would use that info,
reliably captured (inside the DEFINER function to post a task), using
ROLEs and GRANTs and other app-specific permission data.

LOGIN users have different persona in the system, so the current_role
matters, to determine whether the connection posting the task to be
processed asynchronously by a service is allowed or not. I'd think I'm
not the only one that would need something like this, no?

Thanks, --DD



Re: current_role of caller of a DEFINER function

От
Laurenz Albe
Дата:
On Wed, 2024-06-26 at 10:35 +0200, Dominique Devienne wrote:
> So I have two questions:
> 1) Is there any way to know the current_role of the caller of a
> DEFINER function. I fear the answer is no, but better be sure from
> experts here.
> 2) Why isn't there a way to obtain the above? What harm would it be?

Just te be certain, let me ask a question back:

If a SECURITY DEFINER function calls another SECURITY DEFINER function,
which role would you like to get:

1. the invoker that called the first function

2. the owner of the first function (which is the user that called the
   second function)

Yours,
Laurenz Albe



Re: current_role of caller of a DEFINER function

От
Erik Wienhold
Дата:
On 2024-06-26 10:35 +0200, Dominique Devienne wrote:
> Hi. I was led to believe (by an hallucination...) that I could know
> the current_role of the caller of a DEFINER function, but after actual
> experimentation, turns out it shows the OWNER of the function, and not
> the current_role of the caller.
> 
> I foolishly thought curent_role != current_user inside the DEFINER
> function, but reading back the doc, it's clear current_role =
> current_user = user, thus that was wishful thinking. Only session_user
> is representative of the caller, and reliable (modulo SUPERUSER and
> SET AUTHORIZATION, but that's a different story and kinda normal)
> 
> So I have two questions:
> 1) Is there any way to know the current_role of the caller of a
> DEFINER function. I fear the answer is no, but better be sure from
> experts here.

Have you tried capturing current_user with a function parameter and
default value?
https://www.postgresql.org/message-id/f82f70fd-665f-6384-5e8a-987ab9e640d3%40technowledgy.de

-- 
Erik



Re: current_role of caller of a DEFINER function

От
walther@technowledgy.de
Дата:
Dominique Devienne:
> 1) Is there any way to know the current_role of the caller of a
> DEFINER function. I fear the answer is no, but better be sure from
> experts here.

You can do something like this:

CREATE DOMAIN current_user_only AS text
   CONSTRAINT current_user_only CHECK (VALUE = CURRENT_USER);

CREATE FUNCTION func(
   calling_user current_user_only DEFAULT CURRENT_USER
) ... SECURITY DEFINER;

The default value will be evaluated in the context of the calling user, 
the constraint forces it to never be set explicitly to something else.

Thus you can use calling_user inside your function.

Best,

Wolfgang



Re: current_role of caller of a DEFINER function

От
Dominique Devienne
Дата:
On Wed, Jun 26, 2024 at 12:11 PM <walther@technowledgy.de> wrote:
> Dominique Devienne:
> > 1) Is there any way to know the current_role of the caller of a
> > DEFINER function. I fear the answer is no, but better be sure from
> > experts here.
>
> You can do something like this:
>
> CREATE DOMAIN current_user_only AS text
>    CONSTRAINT current_user_only CHECK (VALUE = CURRENT_USER);
>
> CREATE FUNCTION func(
>    calling_user current_user_only DEFAULT CURRENT_USER
> ) ... SECURITY DEFINER;
>
> The default value will be evaluated in the context of the calling user,
> the constraint forces it to never be set explicitly to something else.

Fantastic Wolfgang. Thanks! (again...)

I just tested it in my unit test (unlike last time, see below...), and
it works perfectly.

I tried w/o param, to benefit from the default. OK.
I tried w/ an explicit param, that satisfies the constraint. OK.
I tired w/ an explicit param, that does NOT satisfy the constraint
(i.e. simulating a hack), and it is KO as expected:

ERROR:  value for domain captured_current_role violates check
constraint "equals_current_role"

On Wed, Jun 26, 2024 at 12:06 PM Erik Wienhold <ewie@ewie.name> wrote:
> Have you tried capturing current_user with a function parameter and default value?
> https://www.postgresql.org/message-id/f82f70fd-665f-6384-5e8a-987ab9e640d3%40technowledgy.de

I'm embarrassed to admit that you posted a link to a response to one
of my own threads/questions...
Which Wolfgang in fact had already answered then even. I had
completely forgotten about it, sorry.

On Wed, Jun 26, 2024 at 11:08 AM Laurenz Albe <laurenz.albe@cybertec.at> wrote:
> On Wed, 2024-06-26 at 10:35 +0200, Dominique Devienne wrote:
> > So I have two questions:
> > 1) Is there any way to know the current_role of the caller of a
> > DEFINER function. I fear the answer is no, but better be sure from
> > experts here.
>
> Just to be certain, let me ask a question back:
>
> If a SECURITY DEFINER function calls another SECURITY DEFINER function,
> which role would you like to get:
> 1. the invoker that called the 1st function
> 2. the owner of the 1st function (which is the user that called the 2nd function)

Honestly Laurenz, I didn't think about it, and it does not matter too
much in my case.
Because what matters to me is the initial entry-point, from caller to
DEFINER function,
to accurately capture the role, and then I can pass it on explicitly
myself if needed.
This is for more knowledgeable people to decide on.

I still think such a new variable would be useful,
and simpler than Wolfgang's DOMAIN solution,
but I do have a solution that works right now, and
not in a future version, assuming such a change ever occurs,
so this is already great for me.

Thank you all, --DD



Re: current_role of caller of a DEFINER function

От
"David G. Johnston"
Дата:
On Wednesday, June 26, 2024, Dominique Devienne <ddevienne@gmail.com> wrote:
Only session_user
is representative of the caller, and reliable (modulo SUPERUSER and
SET AUTHORIZATION, but that's a different story and kinda normal)

Why can you not use session_user then?

David J.
 

Re: current_role of caller of a DEFINER function

От
Isaac Morland
Дата:
On Wed, 26 Jun 2024 at 08:42, David G. Johnston <david.g.johnston@gmail.com> wrote:
On Wednesday, June 26, 2024, Dominique Devienne <ddevienne@gmail.com> wrote:
Only session_user
is representative of the caller, and reliable (modulo SUPERUSER and
SET AUTHORIZATION, but that's a different story and kinda normal)

Why can you not use session_user then?

Speaking only for myself, if I am writing a security definer and I go to check the calling role, I want to know the role which was used in the privilege check as to whether the function would even be permitted to be called. What I would be looking for is to behave differently depending on who called me. The original role which connected to the database is totally irrelevant, and could even be a security problem: if superuser does a set role, I shouldn't then be doing security checks which report back that the current role is superuser.

Imagine code like this:

select objects from table where owner = [calling role] …

I think this ties into the related discussions on questions like what search_path should be in effect during trigger execution and during REFRESH MATERIALIZED VIEW and other maintenance commands. It also relates into the question of what role executes triggers and performs calculations during REFRESH MATERIALIZED VIEW and other maintenance commands.

Essentially the current behaviour is quirky and built up over time by a series of individual decisions, and does not appear to have any systematic theory of operation which would answer all these questions all at once.

Re: current_role of caller of a DEFINER function

От
Dominique Devienne
Дата:
On Wed, Jun 26, 2024 at 2:42 PM David G. Johnston
<david.g.johnston@gmail.com> wrote:
> On Wednesday, June 26, 2024, Dominique Devienne <ddevienne@gmail.com> wrote:
>> Only session_user
>> is representative of the caller, and reliable (modulo SUPERUSER and
>> SET AUTHORIZATION, but that's a different story and kinda normal)
>
> Why can you not use session_user then?

Hi. As I already wrote above, the current_role matters in our security model.
The LOGIN user (i.e. session_user) is used only for authentication to
the DB and to connect.
All other security concerns are on other app-maintained (NOLOGIN)
roles, used for authorization. --DD