Skip to content

Commit 27aa6ed

Browse files
authored
Warn the user if a hook function is registered but a necessary parameter is not enabled (#270)
1 parent 3a80a32 commit 27aa6ed

File tree

4 files changed

+221
-2
lines changed

4 files changed

+221
-2
lines changed

pg_tle--1.3.4--1.4.0.sql

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,71 @@ END;
6060
$_pgtleie_$
6161
LANGUAGE plpgsql STRICT;
6262

63+
-- Helper function to register features in the feature_info table
64+
CREATE OR REPLACE FUNCTION pgtle.register_feature(proc regproc, feature pgtle.pg_tle_features)
65+
RETURNS VOID
66+
LANGUAGE plpgsql
67+
AS $$
68+
DECLARE
69+
pg_proc_relid oid;
70+
proc_oid oid;
71+
schema_name text;
72+
nspoid oid;
73+
proname text;
74+
proc_schema_name text;
75+
ident text;
76+
passcheck_enabled text;
77+
clientauth_enabled text;
78+
current_db text;
79+
passcheck_db text;
80+
clientauth_db text;
81+
82+
BEGIN
83+
SELECT setting FROM pg_catalog.pg_settings WHERE name = 'pgtle.enable_password_check' INTO passcheck_enabled;
84+
SELECT setting FROM pg_catalog.pg_settings WHERE name = 'pgtle.enable_clientauth' INTO clientauth_enabled;
85+
SELECT pg_catalog.CURRENT_DATABASE() INTO current_db;
86+
SELECT setting FROM pg_catalog.pg_settings WHERE name = 'pgtle.passcheck_db_name' INTO passcheck_db;
87+
SELECT setting FROM pg_catalog.pg_settings WHERE name = 'pgtle.clientauth_db_name' INTO clientauth_db;
88+
89+
IF feature = 'passcheck' THEN
90+
IF passcheck_enabled = 'off' THEN
91+
RAISE NOTICE 'pgtle.enable_password_check is set to off. To enable passcheck, set pgtle.enable_password_check = on';
92+
ELSE
93+
-- passcheck_db_name is an optional param, we only emit a warning if it's non-empty and is not the current database
94+
IF passcheck_db != '' AND current_db != passcheck_db THEN
95+
RAISE NOTICE '%', pg_catalog.FORMAT('pgtle.passcheck_db_name is currently %I. To trigger this passcheck function, register the function in that database.', passcheck_db)
96+
USING HINT = pg_catalog.FORMAT('Alternatively, to use the current database for passcheck, set pgtle.passcheck_db_name = %I and reload the PostgreSQL configuration.', current_db);
97+
END IF;
98+
END IF;
99+
END IF;
100+
101+
IF feature = 'clientauth' THEN
102+
IF clientauth_enabled = 'off' THEN
103+
RAISE NOTICE 'pgtle.enable_clientauth is set to off. To enable clientauth, set pgtle.enable_clientauth = on';
104+
ELSE
105+
IF current_db != clientauth_db THEN
106+
RAISE NOTICE '%', pg_catalog.FORMAT('pgtle.clientauth_db_name is currently %I. To trigger this clientauth function, register the function in that database.', clientauth_db)
107+
USING HINT = pg_catalog.FORMAT('Alternatively, to use the current database for clientauth, set pgtle.clientauth_db_name = %I and reload the PostgreSQL configuration.', current_db);
108+
END IF;
109+
END IF;
110+
END IF;
111+
112+
SELECT oid into nspoid FROM pg_catalog.pg_namespace
113+
where nspname = 'pg_catalog';
114+
115+
SELECT oid into pg_proc_relid from pg_catalog.pg_class
116+
where relname = 'pg_proc' and relnamespace = nspoid;
117+
118+
SELECT pg_namespace.nspname, pg_proc.oid, pg_proc.proname into proc_schema_name, proc_oid, proname FROM
119+
pg_catalog.pg_namespace, pg_catalog.pg_proc
120+
where pg_proc.oid = proc AND pg_proc.pronamespace = pg_namespace.oid;
121+
122+
SELECT identity into ident FROM pg_catalog.pg_identify_object(pg_proc_relid, proc_oid, 0);
123+
124+
INSERT INTO pgtle.feature_info VALUES (feature, proc_schema_name, proname, ident);
125+
END;
126+
$$;
127+
63128
REVOKE EXECUTE ON FUNCTION pgtle.create_base_type
64129
(
65130
typenamespace regnamespace,
@@ -82,6 +147,12 @@ REVOKE EXECUTE ON FUNCTION pgtle.create_base_type_if_not_exists
82147
storage text
83148
) FROM PUBLIC;
84149

150+
REVOKE EXECUTE ON FUNCTION pgtle.register_feature
151+
(
152+
proc regproc,
153+
feature pgtle.pg_tle_features
154+
) FROM PUBLIC;
155+
85156
GRANT EXECUTE ON FUNCTION pgtle.create_base_type
86157
(
87158
typenamespace regnamespace,
@@ -103,3 +174,9 @@ GRANT EXECUTE ON FUNCTION pgtle.create_base_type_if_not_exists
103174
alignment text,
104175
storage text
105176
) TO pgtle_admin;
177+
178+
GRANT EXECUTE ON FUNCTION pgtle.register_feature
179+
(
180+
proc regproc,
181+
feature pgtle.pg_tle_features
182+
) TO pgtle_admin;

test/expected/pg_tle_api.out

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ SELECT pgtle.register_feature('password_check_length_greater_than_8', 'passcheck
193193
ERROR: duplicate key value violates unique constraint "feature_info_pkey"
194194
DETAIL: Key (feature, schema_name, proname)=(passcheck, public, password_check_length_greater_than_8) already exists.
195195
CONTEXT: SQL statement "INSERT INTO pgtle.feature_info VALUES (feature, proc_schema_name, proname, ident)"
196-
PL/pgSQL function pgtle.register_feature(regproc,pgtle.pg_tle_features) line 24 at SQL statement
196+
PL/pgSQL function pgtle.register_feature(regproc,pgtle.pg_tle_features) line 58 at SQL statement
197197
-- unregister hooks
198198
SELECT pgtle.unregister_feature('password_check_only_nums', 'passcheck');
199199
unregister_feature
@@ -270,6 +270,7 @@ END;
270270
$$
271271
LANGUAGE PLPGSQL;
272272
SELECT pgtle.register_feature('pass.password_check_length_greater_than_8', 'passcheck');
273+
NOTICE: pgtle.enable_password_check is set to off. To enable passcheck, set pgtle.enable_password_check = on
273274
register_feature
274275
------------------
275276

@@ -360,7 +361,110 @@ SELECT pgtle.uninstall_extension('test_unregister_feature');
360361
t
361362
(1 row)
362363

364+
-- create this function one more time to test warning messages
365+
CREATE FUNCTION password_check_length_greater_than_8(username text, shadow_pass text, password_types pgtle.password_types, validuntil_time TimestampTz, validuntil_null boolean) RETURNS void AS
366+
$$
367+
BEGIN
368+
if length(shadow_pass) < 8 THEN
369+
RAISE EXCEPTION 'Passwords needs to be longer than 8';
370+
END IF;
371+
END;
372+
$$
373+
LANGUAGE PLPGSQL;
374+
-- Show warning if passcheck parameter is off when registering a passcheck function
375+
ALTER SYSTEM SET pgtle.enable_password_check = 'off';
376+
SELECT pg_reload_conf();
377+
pg_reload_conf
378+
----------------
379+
t
380+
(1 row)
381+
382+
\c -
383+
SELECT pgtle.register_feature('password_check_length_greater_than_8', 'passcheck');
384+
NOTICE: pgtle.enable_password_check is set to off. To enable passcheck, set pgtle.enable_password_check = on
385+
register_feature
386+
------------------
387+
388+
(1 row)
389+
390+
SELECT pgtle.unregister_feature('password_check_length_greater_than_8', 'passcheck');
391+
unregister_feature
392+
--------------------
393+
394+
(1 row)
395+
396+
-- Show warning if required param is on and db_name is non-empty and not current db
397+
ALTER SYSTEM SET pgtle.enable_password_check = 'on';
398+
ALTER SYSTEM SET pgtle.passcheck_db_name = 'test';
399+
SELECT pg_reload_conf();
400+
pg_reload_conf
401+
----------------
402+
t
403+
(1 row)
404+
405+
\c -
406+
SELECT pgtle.register_feature('password_check_length_greater_than_8', 'passcheck');
407+
NOTICE: pgtle.passcheck_db_name is currently test. To trigger this passcheck function, register the function in that database.
408+
HINT: Alternatively, to use the current database for passcheck, set pgtle.passcheck_db_name = contrib_regression and reload the PostgreSQL configuration.
409+
register_feature
410+
------------------
411+
412+
(1 row)
413+
414+
SELECT pgtle.unregister_feature('password_check_length_greater_than_8', 'passcheck');
415+
unregister_feature
416+
--------------------
417+
418+
(1 row)
419+
420+
-- Show warning if clientauth parameter is off when registering a clientauth function
421+
ALTER SYSTEM SET pgtle.enable_clientauth = 'off';
422+
SELECT pg_reload_conf();
423+
pg_reload_conf
424+
----------------
425+
t
426+
(1 row)
427+
428+
\c -
429+
SELECT pgtle.register_feature('password_check_length_greater_than_8', 'clientauth');
430+
NOTICE: pgtle.enable_clientauth is set to off. To enable clientauth, set pgtle.enable_clientauth = on
431+
register_feature
432+
------------------
433+
434+
(1 row)
435+
436+
SELECT pgtle.unregister_feature('password_check_length_greater_than_8', 'clientauth');
437+
unregister_feature
438+
--------------------
439+
440+
(1 row)
441+
442+
-- Show warning if required param is on and db_name is not current db
443+
ALTER SYSTEM SET pgtle.enable_clientauth = 'on';
444+
ALTER SYSTEM SET pgtle.clientauth_db_name = 'test';
445+
SELECT pg_reload_conf();
446+
pg_reload_conf
447+
----------------
448+
t
449+
(1 row)
450+
451+
\c -
452+
SELECT pgtle.register_feature('password_check_length_greater_than_8', 'clientauth');
453+
NOTICE: pgtle.clientauth_db_name is currently postgres. To trigger this clientauth function, register the function in that database.
454+
HINT: Alternatively, to use the current database for clientauth, set pgtle.clientauth_db_name = contrib_regression and reload the PostgreSQL configuration.
455+
register_feature
456+
------------------
457+
458+
(1 row)
459+
460+
SELECT pgtle.unregister_feature('password_check_length_greater_than_8', 'clientauth');
461+
unregister_feature
462+
--------------------
463+
464+
(1 row)
465+
363466
-- now drop everything
467+
DROP FUNCTION password_check_length_greater_than_8;
364468
DROP SCHEMA pass CASCADE;
365469
NOTICE: drop cascades to function pass.password_check_length_greater_than_8(text,text,pgtle.password_types,timestamp with time zone,boolean)
366470
DROP EXTENSION pg_tle;

test/expected/pg_tle_api_clusterwide.out

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ SELECT pgtle.register_feature('password_check_length_greater_than_8', 'passcheck
198198
ERROR: duplicate key value violates unique constraint "feature_info_pkey"
199199
DETAIL: Key (feature, schema_name, proname)=(passcheck, public, password_check_length_greater_than_8) already exists.
200200
CONTEXT: SQL statement "INSERT INTO pgtle.feature_info VALUES (feature, proc_schema_name, proname, ident)"
201-
PL/pgSQL function pgtle.register_feature(regproc,pgtle.pg_tle_features) line 24 at SQL statement
201+
PL/pgSQL function pgtle.register_feature(regproc,pgtle.pg_tle_features) line 58 at SQL statement
202202
-- unregister hooks
203203
SELECT pgtle.unregister_feature('password_check_only_nums', 'passcheck');
204204
unregister_feature
@@ -275,6 +275,7 @@ END;
275275
$$
276276
LANGUAGE PLPGSQL;
277277
SELECT pgtle.register_feature('pass.password_check_length_greater_than_8', 'passcheck');
278+
NOTICE: pgtle.enable_password_check is set to off. To enable passcheck, set pgtle.enable_password_check = on
278279
register_feature
279280
------------------
280281

test/sql/pg_tle_api.sql

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,43 @@ SELECT EXISTS(
230230
);
231231

232232
SELECT pgtle.uninstall_extension('test_unregister_feature');
233+
-- create this function one more time to test warning messages
234+
CREATE FUNCTION password_check_length_greater_than_8(username text, shadow_pass text, password_types pgtle.password_types, validuntil_time TimestampTz, validuntil_null boolean) RETURNS void AS
235+
$$
236+
BEGIN
237+
if length(shadow_pass) < 8 THEN
238+
RAISE EXCEPTION 'Passwords needs to be longer than 8';
239+
END IF;
240+
END;
241+
$$
242+
LANGUAGE PLPGSQL;
243+
-- Show warning if passcheck parameter is off when registering a passcheck function
244+
ALTER SYSTEM SET pgtle.enable_password_check = 'off';
245+
SELECT pg_reload_conf();
246+
\c -
247+
SELECT pgtle.register_feature('password_check_length_greater_than_8', 'passcheck');
248+
SELECT pgtle.unregister_feature('password_check_length_greater_than_8', 'passcheck');
249+
-- Show warning if required param is on and db_name is non-empty and not current db
250+
ALTER SYSTEM SET pgtle.enable_password_check = 'on';
251+
ALTER SYSTEM SET pgtle.passcheck_db_name = 'test';
252+
SELECT pg_reload_conf();
253+
\c -
254+
SELECT pgtle.register_feature('password_check_length_greater_than_8', 'passcheck');
255+
SELECT pgtle.unregister_feature('password_check_length_greater_than_8', 'passcheck');
256+
-- Show warning if clientauth parameter is off when registering a clientauth function
257+
ALTER SYSTEM SET pgtle.enable_clientauth = 'off';
258+
SELECT pg_reload_conf();
259+
\c -
260+
SELECT pgtle.register_feature('password_check_length_greater_than_8', 'clientauth');
261+
SELECT pgtle.unregister_feature('password_check_length_greater_than_8', 'clientauth');
262+
-- Show warning if required param is on and db_name is not current db
263+
ALTER SYSTEM SET pgtle.enable_clientauth = 'on';
264+
ALTER SYSTEM SET pgtle.clientauth_db_name = 'test';
265+
SELECT pg_reload_conf();
266+
\c -
267+
SELECT pgtle.register_feature('password_check_length_greater_than_8', 'clientauth');
268+
SELECT pgtle.unregister_feature('password_check_length_greater_than_8', 'clientauth');
233269
-- now drop everything
270+
DROP FUNCTION password_check_length_greater_than_8;
234271
DROP SCHEMA pass CASCADE;
235272
DROP EXTENSION pg_tle;

0 commit comments

Comments
 (0)