Re[2]: On login trigger: take three

2022-03-30 Thread Ivan Panchenko

 
Hi, 
>Tue, March 29, 2022, 0:31 +03:00 from Andres Freund :
> 
>Hi,
>
>On 2022-03-28 23:27:56 +0200, Daniel Gustafsson wrote:
>> > On 28 Mar 2022, at 19:10, Andres Freund < and...@anarazel.de > wrote:
>> > On 2022-03-28 15:57:37 +0300,  a.soko...@postgrespro.ru wrote:
>>
>> >> + data initialization. It is vital that any event trigger using the
>> >> + login event checks whether or not the database is in
>> >> + recovery.
>> »
 
>> >> Does any trigger really have to contain a pg_is_in_recovery() call?
>> >
>> > Not *any* trigger, just any trigger that writes.
>>
>> Thats correct, the docs should be updated with something like the below I
>> reckon.
>>
>> It is vital that event trigger using the login event
>> which has side-effects checks whether or not the database is in recovery to
>> ensure they are not performing modifications to hot standby nodes.
>
>Maybe side-effects is a bit too general? Emitting a log message, rejecting a
>login, setting some GUCs, etc are all side-effects too.
Something like this:
 

    
      The login triggers fire also on standby servers.
      To keep them from becoming inaccessible, such triggers should
      avoid writing anything to the database when running on a standby.
      This can be achieved by checking 
pg_is_in_recovery(), see an example below.
    

> 
Also, please fix a typo in doc/src/sgml/ref/create_event_trigger.sgml :
 
- single-user mode and you'll be able to do that. Even triggers can also be
+ single-user mode and you'll be able to do that. Event triggers can also be
 
Regarding the trigger function example:
It does not do anything if run on a standby. To show that it can do something 
on a standby to, I propose to move throwing the night exception to the 
beginning.
So it will be:
 
CREATE OR REPLACE FUNCTION init_session() 
RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS 
$$ 
DECLARE 
  hour integer = EXTRACT('hour' FROM current_time); 
  rec boolean;
BEGIN

-- 1) Forbid logging in late:
IF hour BETWEEN 2 AND 4 THEN
  RAISE EXCEPTION 'Login forbidden';  -- do not allow to login these hours
END IF;

-- The remaining stuff cannot be done on standbys,
-- so ensure the database is not in recovery
SELECT pg_is_in_recovery() INTO rec;
IF rec THEN
  RETURN;
END IF

-- 2) Assign some roles

IF hour BETWEEN 8 AND 20 THEN -- at daytime grant the day_worker role
  EXECUTE 'REVOKE night_worker FROM ' || quote_ident(session_user);
  EXECUTE 'GRANTday_worker TO '   || quote_ident(session_user);
ELSE  -- at other time grant the night_worker 
role
  EXECUTE 'REVOKE day_worker FROM ' || quote_ident(session_user);
  EXECUTE 'GRANT  night_worker TO ' || quote_ident(session_user);
END IF;

-- 3) Initialize some user session data

CREATE TEMP TABLE session_storage (x float, y integer);

-- 4) Log the connection time

INSERT INTO user_login_log VALUES (session_user, current_timestamp);

END;
$$;
Finally, let me propose to append to the regression test the following:
 
 
\c 
SELECT dathasloginevt FROM pg_database WHERE datname= :'DBNAME';
 
which should output:
 dathasloginevt 

 f
(1 row)
 
So we can check that removal of the event trigger resets this flag in 
pg_database. Note that reconnect (\c) is necessary here.
 
Regards,
Ivan
 
>
>> >> In this message
>> >> ( 
>> >> https://www.postgresql.org/message-id/20220312024652.lvgehszwke4hhove%40alap3.anarazel.de
>> >>  )
>> >> it was only about triggers on hot standby, which run not read-only queries
>> >
>> > The problem precisely is that the login triggers run on hot standby nodes, 
>> > and
>> > that if they do writes, you can't login anymore.
>>
>> Do you think this potential foot-gun is scary enough to reject this patch?
>> There are lots of creative ways to cause Nagios alerts from ones database, 
>> but
>> this has the potential to do so with a small bug in userland code. Still, I
>> kind of like the feature so I'm indecisive.
>
>It does seem like a huge footgun. But also kinda useful. So I'm really +-0.
>
>Greetings,
>
>Andres Freund
 

Re[2]: On login trigger: take three

2021-11-03 Thread Ivan Panchenko

Dear colleagues, 
Please see my suggestions below and the updated patch attached.
 
 
 
 
  
>Среда, 29 сентября 2021, 15:14 +03:00 от Teodor Sigaev < teo...@sigaev.ru >:
> 
>Hi!
>
>Nice feature, but, sorry, I see some design problem in suggested feature. 
>AFAIK,
>there is two use cases for this feature:
>1 A permission / prohibition to login some users
>2 Just a logging of facts of user's login
>
>Suggested patch proposes prohibition of login only by failing of login trigger
>and it has at least two issues:
>1 In case of prohibition to login, there is no clean way to store information
>about unsuccessful login. Ok, it could be solved by dblink module but it seems
>to scary.
This is a common problem of logging errors and unsuccessful transactions of any 
kind. It can be solved by:
- logging to external log storage (stupid logging to files or syslog or 
whatever you can imagine with PL/Perl (sorry))
- logging inside the database by db_link or through background worker (like 
described in  
https://dpavlin.wordpress.com/2017/05/09/david-rader-autonomous-transactions-using-pg_background/
 )
- or by implementing autonomous transactions in PostgreSQL, which is already 
under development by some of my and Teodor’s colleagues.
 
So I propose not to invent another solution to this common problem here.
>2 For logging purpose failing of trigger will cause impossibility to login, it
>could be workarounded by catching error in trigger function, but it's not so
>obvious for DBA.
If the trigger contains an error, nobody can login. The database is bricked.
Previous variant of the patch proposed to fix this with going to single-user 
mode.
For faster recovery I propose to have also a GUC variable to turn on/off the 
login triggers. It should be 'on' by default.
>
>some other issues:
>3 It's easy to create security hole, see attachment where non-privileged user
>can close access to database even for superuser.
Such cases can be avoided by careful design of the login triggers and related 
permissions. Added such note to the documentation.
>4 Feature is not applicable for logging unsuccessful login with wrong
>username/password or not matched by pg_hba.conf. Oracle could operate with such
>cases. But I don't think that this issue is a stopper for the patch.
Yes. Btw, note that pg_hba functionality can be implemented completely inside 
the login trigger :) !
>
>May be, to solve that issues we could introduce return value of trigger and/or
>add something like IGNORE ERROR to CREATE EVENT TRIGGER command.
Any solutions which make syntax more complicated can lead Postgres to become 
Oracle (in the worst sense). I do not like this.

A new version of the patch is attached. It applies to the current master and 
contains the above mentioned GUC code, relevant tests and docs.
Regards,
Ivan Panchenko
>
>On 15.09.2021 16:32, Greg Nancarrow wrote:
>> On Wed, Sep 8, 2021 at 10:56 PM Daniel Gustafsson < dan...@yesql.se > wrote:
>>>
>>> I took a look at this, and while I like the proposed feature I think the 
>>> patch
>>> has a bit more work required.
>>>
>>
>> Thanks for reviewing the patch.
>> I am not the original patch author (who no longer seems active) but
>> I've been contributing a bit and keeping the patch alive because I
>> think it's a worthwhile feature.
>>
>>>
>>> +
>>> +-- 2) Initialize some user session data
>>> + CREATE TEMP TABLE session_storage (x float, y integer);
>>> The example in the documentation use a mix of indentations, neither of 
>>> which is
>>> the 2-space indentation used elsewhere in the docs.
>>>
>>
>> Fixed, using 2-space indentation.
>> (to be honest, the indentation seems inconsistent elsewhere in the
>> docs e.g. I'm seeing a nearby case of 2-space on 1st indent, 6-space
>> on 2nd indent)
>>
>>>
>>> + /* Get the command tag. */
>>> + tag = parsetree ? CreateCommandTag(parsetree) : CMDTAG_CONNECT;
>>> This is hardcoding knowledge that currently only this trigger wont have a
>>> parsetree, and setting the tag accordingly. This should instead check the
>>> event and set CMDTAG_UNKNOWN if it isn't the expected one.
>>>
>>
>> I updated that, but maybe not exactly how you expected?
>>
>>>
>>> + /* database has on-login triggers */
>>> + bool dathaslogontriggers;
>>> This patch uses three different names for the same thing: client connection,
>>> logontrigger and login trigger. Since this trigger only fires after 
>>> successful
>>> authentication it’s not accurate to name it client connection, as that 
>>> implies
>>> it running on connections rather than logins. The nomenclature used in the
>>> tree is "login" so the patch should be adjusted everywhere to use that.
>>>
>>
>> Fixed.
>>
>>>
>>> +/* Hook for plugins to get control at start of session */
>>> +client_connection_hook_type client_connection_hook = EventTriggerOnConnect;
>>> I don't see the reason for adding core functionality by hooks. Having a hook
>>> might be a useful thing on its own (to be discussed in a new thread, not 
>>> hidden
>>> 

Re[2]: On login trigger: take three

2021-03-16 Thread Ivan Panchenko

Hi,

Thank you, Konstantin, for this very good feature with numerous use cases.
Please find the modified patch attached.

I’ve added the ‘enable_client_connection_trigger’ GUC to the sample config file 
and also an additional example page to the docs.
Check world has passed and it is ready for committer.
  
>Четверг, 28 января 2021, 12:04 +03:00 от Konstantin Knizhnik 
>:
> 
>
>
>On 28.01.2021 5:47, Amit Kapila wrote:
>> On Mon, Dec 28, 2020 at 5:46 PM Masahiko Sawada < sawada.m...@gmail.com > 
>> wrote:
>>> On Sat, Dec 26, 2020 at 4:04 PM Pavel Stehule < pavel.steh...@gmail.com > 
>>> wrote:


 so 26. 12. 2020 v 8:00 odesílatel Pavel Stehule < pavel.steh...@gmail.com 
 > napsal:
> Hi
>
>
>> Thank you.
>> I have applied all your fixes in on_connect_event_trigger-12.patch.
>>
>> Concerning enable_client_connection_trigger GUC, I think that it is 
>> really useful: it is the fastest and simplest way to disable login 
>> triggers in case
>> of some problems with them (not only for superuser itself, but for all 
>> users). Yes, it can be also done using "ALTER EVENT TRIGGER DISABLE".
>> But assume that you have a lot of databases with different login 
>> policies enforced by on-login event triggers. And you want temporary 
>> disable them all, for example for testing purposes.
>> In this case GUC is most convenient way to do it.
>>
> There was typo in patch
>
> diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
> index f810789..8861f1b 100644
> --- a/doc/src/sgml/config.sgml
> +++ b/doc/src/sgml/config.sgml
> @@ -1,4 +1,4 @@
> -
> +\
>
> I have not any objections against functionality or design. I tested the 
> performance, and there are no negative impacts when this feature is not 
> used. There is significant overhead related to plpgsql runtime 
> initialization, but when this trigger will be used, then probably some 
> other PLpgSQL procedures and functions will be used too, and then this 
> overhead can be ignored.
>
> * make without warnings
> * make check-world passed
> * doc build passed
>
> Possible ToDo:
>
> The documentation can contain a note so usage connect triggers in 
> environments with short life sessions and very short fast queries without 
> usage PLpgSQL functions or procedures can have negative impact on 
> performance due overhead of initialization of PLpgSQL engine.
>
> I'll mark this patch as ready for committers

 looks so this patch has not entry in commitfestapp 2021-01

>>> Yeah, please register this patch before the next CommitFest[1] starts,
>>> 2021-01-01 AoE[2].
>>>
>> Konstantin, did you register this patch in any CF? Even though the
>> reviewer seems to be happy with the patch, I am afraid that we might
>> lose track of this unless we register it.
>> Yes, certainly:
>https://commitfest.postgresql.org/31/2900/
>
>--
>Konstantin Knizhnik
>Postgres Professional:  http://www.postgrespro.com
>The Russian Postgres Company
>
>  
 
 
 
 

on_connect_event_trigger-13a.patch
Description: Binary data