summaryrefslogtreecommitdiff
path: root/doc/src
diff options
context:
space:
mode:
authorAlexander Korotkov2023-10-16 00:16:55 +0000
committerAlexander Korotkov2023-10-16 00:18:22 +0000
commite83d1b0c40ccda8955f1245087f0697652c4df86 (patch)
treea71713272ad1fef3a8e331f0321ed82237f65dbc /doc/src
parentc558e6fd92ffeb85d5f52e32ccbcf8a5b5eb7bf3 (diff)
Add support event triggers on authenticated login
This commit introduces trigger on login event, allowing to fire some actions right on the user connection. This can be useful for logging or connection check purposes as well as for some personalization of environment. Usage details are described in the documentation included, but shortly usage is the same as for other triggers: create function returning event_trigger and then create event trigger on login event. In order to prevent the connection time overhead when there are no triggers the commit introduces pg_database.dathasloginevt flag, which indicates database has active login triggers. This flag is set by CREATE/ALTER EVENT TRIGGER command, and unset at connection time when no active triggers found. Author: Konstantin Knizhnik, Mikhail Gribkov Discussion: https://postgr.es/m/0d46d29f-4558-3af9-9c85-7774e14a7709%40postgrespro.ru Reviewed-by: Pavel Stehule, Takayuki Tsunakawa, Greg Nancarrow, Ivan Panchenko Reviewed-by: Daniel Gustafsson, Teodor Sigaev, Robert Haas, Andres Freund Reviewed-by: Tom Lane, Andrey Sokolov, Zhihong Yu, Sergey Shinderuk Reviewed-by: Gregory Stark, Nikita Malakhov, Ted Yu
Diffstat (limited to 'doc/src')
-rw-r--r--doc/src/sgml/bki.sgml2
-rw-r--r--doc/src/sgml/catalogs.sgml13
-rw-r--r--doc/src/sgml/ecpg.sgml2
-rw-r--r--doc/src/sgml/event-trigger.sgml94
4 files changed, 110 insertions, 1 deletions
diff --git a/doc/src/sgml/bki.sgml b/doc/src/sgml/bki.sgml
index f71644e3989..315ba819514 100644
--- a/doc/src/sgml/bki.sgml
+++ b/doc/src/sgml/bki.sgml
@@ -184,7 +184,7 @@
descr => 'database\'s default template',
datname => 'template1', encoding => 'ENCODING',
datlocprovider => 'LOCALE_PROVIDER', datistemplate => 't',
- datallowconn => 't', datconnlimit => '-1', datfrozenxid => '0',
+ datallowconn => 't', dathasloginevt => 'f', datconnlimit => '-1', datfrozenxid => '0',
datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE',
datctype => 'LC_CTYPE', daticulocale => 'ICU_LOCALE', datacl => '_null_' },
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index e09adb45e41..d3458840fbe 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -3037,6 +3037,19 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
<row>
<entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>dathasloginevt</structfield> <type>bool</type>
+ </para>
+ <para>
+ Indicates that there are login event triggers defined for this database.
+ This flag is used to avoid extra lookups on the
+ <structname>pg_event_trigger</structname> table during each backend
+ startup. This flag is used internally by <productname>PostgreSQL</productname>
+ and should not be manually altered or read for monitoring purposes.
+ </para></entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
<structfield>datconnlimit</structfield> <type>int4</type>
</para>
<para>
diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml
index f52165165dc..54de81158b5 100644
--- a/doc/src/sgml/ecpg.sgml
+++ b/doc/src/sgml/ecpg.sgml
@@ -4769,6 +4769,7 @@ datdba = 10 (type: 1)
encoding = 0 (type: 5)
datistemplate = t (type: 1)
datallowconn = t (type: 1)
+dathasloginevt = f (type: 1)
datconnlimit = -1 (type: 5)
datfrozenxid = 379 (type: 1)
dattablespace = 1663 (type: 1)
@@ -4793,6 +4794,7 @@ datdba = 10 (type: 1)
encoding = 0 (type: 5)
datistemplate = f (type: 1)
datallowconn = t (type: 1)
+dathasloginevt = f (type: 1)
datconnlimit = -1 (type: 5)
datfrozenxid = 379 (type: 1)
dattablespace = 1663 (type: 1)
diff --git a/doc/src/sgml/event-trigger.sgml b/doc/src/sgml/event-trigger.sgml
index 3b6a5361b34..10b20f0339a 100644
--- a/doc/src/sgml/event-trigger.sgml
+++ b/doc/src/sgml/event-trigger.sgml
@@ -28,6 +28,7 @@
An event trigger fires whenever the event with which it is associated
occurs in the database in which it is defined. Currently, the only
supported events are
+ <literal>login</literal>,
<literal>ddl_command_start</literal>,
<literal>ddl_command_end</literal>,
<literal>table_rewrite</literal>
@@ -36,6 +37,24 @@
</para>
<para>
+ The <literal>login</literal> event occurs when an authenticated user logs
+ into the system. Any bug in a trigger procedure for this event may
+ prevent successful login to the system. Such bugs may be fixed by
+ setting <xref linkend="guc-event-triggers"/> is set to <literal>false</literal>
+ either in a connection string or configuration file. Alternative is
+ restarting the system in single-user mode (as event triggers are
+ disabled in this mode). See the <xref linkend="app-postgres"/> reference
+ page for details about using single-user mode.
+ The <literal>login</literal> event will also fire on standby servers.
+ To prevent servers from becoming inaccessible, such triggers must avoid
+ writing anything to the database when running on a standby.
+ Also, it's recommended to avoid long-running queries in
+ <literal>login</literal> event triggers. Notes that, for instance,
+ cancelling connection in <application>psql</application> wouldn't cancel
+ the in-progress <literal>login</literal> trigger.
+ </para>
+
+ <para>
The <literal>ddl_command_start</literal> event occurs just before the
execution of a <literal>CREATE</literal>, <literal>ALTER</literal>, <literal>DROP</literal>,
<literal>SECURITY LABEL</literal>,
@@ -1300,4 +1319,79 @@ CREATE EVENT TRIGGER no_rewrite_allowed
</programlisting>
</para>
</sect1>
+
+ <sect1 id="event-trigger-database-login-example">
+ <title>A Database Login Event Trigger Example</title>
+
+ <para>
+ The event trigger on the <literal>login</literal> event can be
+ useful for logging user logins, for verifying the connection and
+ assigning roles according to current circumstances, or for session
+ data initialization. It is very important that any event trigger using
+ the <literal>login</literal> event checks whether or not the database is
+ in recovery before performing any writes. Writing to a standby server
+ will make it inaccessible.
+ </para>
+
+ <para>
+ The following example demonstrates these options.
+<programlisting>
+-- create test tables and roles
+CREATE TABLE user_login_log (
+ "user" text,
+ "session_start" timestamp with time zone
+);
+CREATE ROLE day_worker;
+CREATE ROLE night_worker;
+
+-- the example trigger function
+CREATE OR REPLACE FUNCTION init_session()
+ RETURNS event_trigger SECURITY DEFINER
+ LANGUAGE plpgsql AS
+$$
+DECLARE
+ hour integer = EXTRACT('hour' FROM current_time at time zone 'utc');
+ rec boolean;
+BEGIN
+-- 1. Forbid logging in between 2AM and 4AM.
+IF hour BETWEEN 2 AND 4 THEN
+ RAISE EXCEPTION 'Login forbidden';
+END IF;
+
+-- The checks below cannot be performed on standby servers so
+-- ensure the database is not in recovery before we perform any
+-- operations.
+SELECT pg_is_in_recovery() INTO rec;
+IF rec THEN
+ RETURN;
+END IF;
+
+-- 2. Assign some roles. At daytime, grant the day_worker role, else the
+-- night_worker role.
+IF hour BETWEEN 8 AND 20 THEN
+ EXECUTE 'REVOKE night_worker FROM ' || quote_ident(session_user);
+ EXECUTE 'GRANT day_worker TO ' || quote_ident(session_user);
+ELSE
+ EXECUTE 'REVOKE day_worker FROM ' || quote_ident(session_user);
+ EXECUTE 'GRANT night_worker TO ' || quote_ident(session_user);
+END IF;
+
+-- 3. Initialize user session data
+CREATE TEMP TABLE session_storage (x float, y integer);
+ALTER TABLE session_storage OWNER TO session_user;
+
+-- 4. Log the connection time
+INSERT INTO public.user_login_log VALUES (session_user, current_timestamp);
+
+END;
+$$;
+
+-- trigger definition
+CREATE EVENT TRIGGER init_session
+ ON login
+ EXECUTE FUNCTION init_session();
+ALTER EVENT TRIGGER init_session ENABLE ALWAYS;
+</programlisting>
+ </para>
+ </sect1>
</chapter>