Skip to content

Commit e838577

Browse files
authored
Create login _ password
1 parent fa4aed3 commit e838577

File tree

1 file changed

+293
-0
lines changed

1 file changed

+293
-0
lines changed

login _ password

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
-- Sequence aanmaken; als een nieuw login wordt aangemaakt door de WH-kant, zal een oneven ID worden uitgegeven.
2+
-- Als een nieuw ID wordt gegenereerd aan de datamart-kant, dan een even ID worden uitgegeven.
3+
CREATE SEQUENCE wh.login__login_id_seq
4+
INCREMENT 2
5+
START 1
6+
MINVALUE 1
7+
MAXVALUE 2147483647
8+
CACHE 1;
9+
ALTER SEQUENCE wh.login__login_id_seq OWNER TO dwh_owner;
10+
11+
12+
-- Table: wh.login
13+
-- DROP TABLE wh.login;
14+
CREATE TABLE wh.login (
15+
login_id INTEGER NOT NULL DEFAULT NEXTVAL('wh.login__login_id_seq'::REGCLASS),
16+
login CHARACTER VARYING(33) NOT NULL,
17+
login_type_id INTEGER NOT NULL,
18+
naam CHARACTER VARYING(100) NOT NULL,
19+
is_vrouw BOOLEAN NOT NULL DEFAULT TRUE,
20+
emailadres CHARACTER VARYING(254) NOT NULL DEFAULT 'user@example.com',
21+
salt CHARACTER VARYING(29) NOT NULL DEFAULT generic.GEN_SALT('BF',13),
22+
wachtwoord CHARACTER VARYING(60) NOT NULL,
23+
secret_key CHARACTER VARYING(32) NOT NULL DEFAULT generic.gen_rnd_base32(32),
24+
geldig_vanaf_ts TIMESTAMP NOT NULL DEFAULT CLOCK_TIMESTAMP(),
25+
CONSTRAINT pk_login PRIMARY KEY (login),
26+
CONSTRAINT fk_login__login_type FOREIGN KEY (login_type_id) REFERENCES wh.login_type (login_type_id) ON UPDATE NO ACTION ON DELETE NO ACTION
27+
);
28+
ALTER TABLE wh.login OWNER TO dwh_owner;
29+
GRANT SELECT ON TABLE wh.login TO dwh_readonly;
30+
31+
-- Index: idx_login__login_naam
32+
-- DROP INDEX idx_login__login_naam;
33+
CREATE UNIQUE INDEX idx_login__login_id ON wh.login (login_id) INCLUDE(login, naam);
34+
35+
CREATE POLICY plc_rls_login ON wh.login USING (login = SESSION_USER);
36+
37+
REVOKE SELECT ON TABLE wh.login FROM xxxxx;
38+
GRANT SELECT (login_id, login, login_type_id, naam, is_vrouw, emailadres, salt, wachtwoord, geldig_vanaf_ts) ON TABLE wh.login TO xxxxxxx;
39+
40+
41+
/* */
42+
CREATE OR REPLACE FUNCTION wh.fnc_sync_login_role()
43+
RETURNS TRIGGER AS
44+
45+
$BODY$
46+
DECLARE
47+
-- INSERT-waarden:
48+
_login TEXT;
49+
_login_id INTEGER;
50+
_wachtwoord TEXT;
51+
52+
_aantal INT;
53+
_aantal_versies INT;
54+
_aantal_dagen_valid INT;
55+
56+
-- Einddatum geldigheid wachtwoord bepalen
57+
_geldig_tot TEXT;
58+
59+
BEGIN
60+
-- Aantal versies van het wachtwoord 'onthouden'
61+
_aantal_versies := 5;
62+
-- Aantal dagen dat een wachtwoord geldig blijft
63+
-- Eventueel vanuit een meta-tabel ophalen, waarmee 'dynamisch'
64+
_aantal_dagen_valid := 60;
65+
66+
-- Corrigeren
67+
NEW.login := LOWER(BTRIM(NEW.login));
68+
69+
IF TG_OP = 'INSERT' THEN
70+
-- Voor een INSERT, zou het login_id NULL moeten zijn en login NIET NULL
71+
IF NEW.login ~ '^_[\da-f]{32}$' THEN
72+
-- Bestaat de login reeds in wh.login?
73+
SELECT login_id, login INTO _login_id, _login
74+
FROM wh.login
75+
WHERE login = NEW.login;
76+
77+
IF NOT FOUND THEN
78+
-- Deze mogen we toevoegen als ROLE, vermits deze niet al bestaat.
79+
-- Bestaat deze ROLE dus al?
80+
PERFORM 1
81+
FROM pg_catalog.pg_roles
82+
WHERE LOWER(rolname) = NEW.login;
83+
84+
-- ROLE bestaat dus niet - aanmaken:
85+
IF NOT FOUND THEN
86+
-- Salt genereren
87+
NEW.salt = generic.GEN_SALT('BF',13);
88+
89+
-- Feitelijk de ROLE aanmaken
90+
IF NEW.wachtwoord IS NULL THEN
91+
-- Geldig-tot bepalen ; dit is de geldigheidsduur van het account / ROLE. Als het wachtwoord leeg wordt gelaten, deze dan gelijk nemen aan het login ('_'+MD5(emailadres))
92+
-- Zodra het wachtwoord gewijzigd wordt, word ook de geldigheidsduur aangepast.
93+
SELECT (CURRENT_TIMESTAMP + INTERVAL '7 DAY')::TEXT INTO _geldig_tot; --Inclusief het huidige tijdstip...
94+
-- Wachtwoord is niet ingevuld, dus default op de gebruikersnaam instellen
95+
EXECUTE FORMAT('CREATE ROLE %s ENCRYPTED PASSWORD %s NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN NOREPLICATION NOBYPASSRLS VALID UNTIL %s;' , NEW.login, QUOTE_LITERAL(NEW.login), QUOTE_LITERAL(_geldig_tot) );
96+
97+
-- Nu het 'wachtwoord' omwerken naar de encrypted variant
98+
NEW.wachtwoord = generic.CRYPT(NEW.login,NEW.salt);
99+
ELSE
100+
-- Geldig-tot bepalen ; 60 dagen voor een net, ingevuld en goedgekeurd wachtwoord
101+
EXECUTE FORMAT ('SELECT (CURRENT_TIMESTAMP + INTERVAL ''%s DAY'')::TEXT', _aantal_dagen_valid) INTO _geldig_tot;
102+
EXECUTE FORMAT('SET password_encryption = ''SCRAM-SHA-256'';');
103+
EXECUTE FORMAT('CREATE ROLE %s ENCRYPTED PASSWORD %s NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN NOREPLICATION NOBYPASSRLS VALID UNTIL %s;' , NEW.login, QUOTE_LITERAL(NEW.wachtwoord), QUOTE_LITERAL(_geldig_tot) );
104+
105+
-- Nu het opgegeven wachtwoord omwerken naar de encrypted variant
106+
NEW.wachtwoord = generic.CRYPT(NEW.wachtwoord,NEW.salt);
107+
108+
END IF;
109+
110+
-- Nieuwe wachtwoord / salt kopieren naar wh.login_wachtwoord
111+
EXECUTE FORMAT ('INSERT INTO wh.login_wachtwoord (login_id, login, salt, wachtwoord, geldig_vanaf_ts) VALUES(%s,%s,%s,%s,CLOCK_TIMESTAMP());',
112+
NEW.login_id, NEW.login, QUOTE_LITERAL(NEW.salt), QUOTE_LITERAL(NEW.wachtwoord));
113+
114+
-- Rechten
115+
EXECUTE FORMAT ('GRANT web_app_login TO %s ;', NEW.login);
116+
EXECUTE FORMAT ('GRANT web_login TO %s ;', NEW.login);
117+
118+
-- Het wachtwoord-type zetten op 'SCRAM-SHA-256'
119+
EXECUTE FORMAT ('ALTER ROLE %s SET password_encryption = ''SCRAM-SHA-256'';', NEW.login);
120+
RETURN NEW;
121+
ELSE
122+
-- ROLE bestaat al
123+
RAISE NOTICE 'ROLE % bestaat al - niet aangemaakt en geen INSERT gedaan!', _login;
124+
RETURN NULL;
125+
END IF;
126+
ELSE
127+
-- Gevonden, dus bestaat al
128+
RAISE NOTICE 'Login % bestaat al (geregistreerd onder id: %)', NEW.login, _login_id;
129+
RETURN NULL;
130+
END IF;
131+
ELSE
132+
-- Melding doen
133+
RAISE NOTICE 'Login % voldoet niet aan de regels van een login ("_"+MD5(emailadres))', NEW.login;
134+
135+
-- TODO: eventueel nog een ROLE aanmaken (default apotheker) op basis van emailadres... (tenzij emailadres leeg)
136+
RETURN NULL; -- Verder niets meer doen, dus de INSERT feitelijk annuleren
137+
END IF;
138+
139+
-- ------------------------------------------------------------------------------------------------
140+
ELSEIF TG_OP = 'UPDATE' THEN
141+
-- Is wachtwoord gewijzigd?
142+
IF OLD.wachtwoord != NEW.wachtwoord THEN
143+
IF NEW.salt = OLD.salt OR NEW.salt !~ '^\$2a\$13\$' OR LENGTH(NEW.salt) != 29 THEN
144+
-- Nieuwe SALT voldoet niet
145+
NEW.salt = generic.GEN_SALT('BF',13);
146+
END IF;
147+
148+
-- LOGIN (=ROLE) bepalen
149+
SELECT login, login_id INTO _login, _login_id
150+
FROM wh.login
151+
WHERE login_id = NEW.login_id;
152+
153+
-- Nu de controle of dit wachtwoord 'mag' - oftewel, het is niet gelijk aan één
154+
-- van de laatste 5 wachtwoorden.
155+
-- LET OP: Dit duurt wat langer, vanwege het bepalen van maximaal _aantal_versies de Blowfish(13)
156+
PERFORM TRUE
157+
FROM wh.login_wachtwoord AS lw
158+
WHERE lw.login_id = _login_id AND
159+
generic.CRYPT(NEW.wachtwoord,salt) = lw.wachtwoord
160+
;
161+
162+
IF NOT FOUND THEN
163+
-- JA, dit wachtwoord 'mag'
164+
165+
-- Wachtwoord van de ROLE wijzigen voordat deze wordt ge-encrypt
166+
EXECUTE FORMAT('SET password_encryption = ''SCRAM-SHA-256'';');
167+
EXECUTE FORMAT('ALTER ROLE %s PASSWORD %s;', _login, QUOTE_LITERAL(NEW.wachtwoord));
168+
169+
-- En de geldigheid aanpassen
170+
EXECUTE FORMAT ('SELECT (CURRENT_TIMESTAMP + INTERVAL ''%s DAY'')::TEXT', _aantal_dagen_valid) INTO _geldig_tot;
171+
EXECUTE FORMAT('ALTER ROLE %s VALID UNTIL %s;', _login, QUOTE_LITERAL(_geldig_tot));
172+
173+
-- De Blowfish-variant:
174+
NEW.wachtwoord = CRYPT(NEW.wachtwoord,NEW.salt);
175+
176+
-- Nieuwe wachtwoord / salt kopieren naar wh.login_wachtwoord
177+
EXECUTE FORMAT ('INSERT INTO wh.login_wachtwoord (login_id, login, salt, wachtwoord, geldig_vanaf_ts) VALUES(%s,%s,%s,%s,CLOCK_TIMESTAMP());',
178+
_login_id, NEW.login, QUOTE_LITERAL(NEW.salt), QUOTE_LITERAL(NEW.wachtwoord));
179+
180+
ELSE
181+
-- NEE, dit wachtwoord mag niet; melding maken
182+
RAISE NOTICE 'Het wachtwoord "%" (login_id: %) is gelijk aan één van de laatste 5 wachtwoorden - niet toegestaan; wachtwoord (en salt) NIET gewijzigd.', NEW.wachtwoord, NEW.login_id;
183+
-- Laten zoals het was:
184+
NEW.wachtwoord = OLD.wachtwoord;
185+
NEW.salt = OLD.salt;
186+
END IF;
187+
188+
END IF; -- Einde wachtwoord gewijzigd
189+
190+
-- Is LOGIN gewijzigd?
191+
IF NEW.login != OLD.login THEN
192+
-- Het wachtwoord is NIET langer 'afhankelijk' is van de ROLE (zoals in het geval van het MD5-wachtwoord)
193+
-- (vanwege gebruik SCRAM-SHA-256) en hoeft daarom ook niet gewijzigd te worden.
194+
EXECUTE FORMAT('ALTER ROLE %s RENAME TO %s;', OLD.login, NEW.login);
195+
END IF; -- Einde Login gewijzigd
196+
197+
RETURN NEW; -- Update gewoon uitvoeren
198+
-- ------------------------------------------------------------------------------------------------
199+
ELSEIF TG_OP = 'DELETE' THEN
200+
-- ROLE bepalen:
201+
SELECT login_id, login INTO _login_id, _login
202+
FROM wh.login
203+
WHERE login = OLD.login;
204+
205+
-- 'Gewoon' verwijderen
206+
EXECUTE FORMAT('DROP USER IF EXISTS %s;',LOWER(OLD.login));
207+
RAISE NOTICE 'Verwijderen ROLE "%" (delete id: %)', _login, _login_id;
208+
RETURN NEW; -- En de delete gewoon laten uitvoeren
209+
-- ------------------------------------------------------------------------------------------------
210+
ELSEIF TG_OP = 'TRUNCATE' THEN
211+
-- Dus een 'truncate'; alle users conform wh.login verwijderen
212+
FOR _login IN SELECT login FROM wh.login LOOP
213+
RAISE NOTICE 'Verwijderen gebruiker "%", vanwege truncate', _login;
214+
EXECUTE 'DROP USER IF EXISTS ' || LOWER(_login) || ';';
215+
END LOOP;
216+
RETURN OLD; -- ... de truncate gewoon laten uitvoeren
217+
-- ------------------------------------------------------------------------------------------------
218+
END IF;
219+
220+
END;
221+
222+
$BODY$
223+
LANGUAGE plpgsql;
224+
225+
ALTER FUNCTION wh.fnc_sync_login_role() OWNER TO dwh_owner;
226+
227+
-- Trigger: trg_login_bijwerken on login
228+
-- DROP TRIGGER trg_login_bijwerken ON login;
229+
CREATE TRIGGER trg_login_bijwerken
230+
BEFORE INSERT OR UPDATE OR DELETE
231+
ON wh.login
232+
FOR EACH ROW
233+
EXECUTE PROCEDURE wh.fnc_sync_login_role();
234+
CREATE TRIGGER trg_login_truncate
235+
BEFORE TRUNCATE
236+
ON wh.login
237+
EXECUTE PROCEDURE wh.fnc_sync_login_role();
238+
239+
240+
/* ------------------------------------------------------------------------------------------------------------------------------------------------------------- */
241+
/* ------------------------------------------------------------------------------------------------------------------------------------------------------------- */
242+
243+
-- Table: login_wachtwoord
244+
-- DROP TABLE login_wachtwoord;
245+
CREATE TABLE wh.login_wachtwoord(
246+
login_id INTEGER NOT NULL,
247+
login CHARACTER VARYING(33) NOT NULL,
248+
geldig_vanaf_ts TIMESTAMP(6) WITH TIME ZONE NOT NULL DEFAULT CLOCK_TIMESTAMP(),
249+
salt CHARACTER VARYING(29) NOT NULL DEFAULT generic.GEN_SALT('BF',13),
250+
wachtwoord CHARACTER VARYING(60) NOT NULL,
251+
CONSTRAINT pk_login_wachtwoord PRIMARY KEY (login_id, login, geldig_vanaf_ts),
252+
CONSTRAINT fk_login_wachtwoord__login FOREIGN KEY (login) REFERENCES wh.login (login) ON UPDATE CASCADE ON DELETE CASCADE INITIALLY DEFERRED
253+
);
254+
ALTER TABLE wh.login_wachtwoord OWNER TO dwh_owner;
255+
GRANT SELECT ON TABLE wh.login_wachtwoord TO GROUP dwh_readonly;
256+
CREATE POLICY plc_rls_login_wachtwoord ON wh.login_wachtwoord USING (login = SESSION_USER);
257+
258+
/* Functie voor het maximeren van het aantal 'onthouden' wachtwoorden */
259+
CREATE OR REPLACE FUNCTION wh.fnc_prune_pw_history()
260+
RETURNS TRIGGER AS
261+
262+
$BODY$
263+
DECLARE
264+
_aantal_versies INT; -- Aantal versies van het wachtwoord dat bewaard moet blijven
265+
BEGIN
266+
-- Vijf historische en het huidige (5+1)
267+
_aantal_versies := 6;
268+
269+
DELETE FROM wh.login_wachtwoord AS lw
270+
USING ( SELECT login_id,
271+
geldig_vanaf_ts
272+
FROM ( SELECT login_id,
273+
geldig_vanaf_ts,
274+
ROW_NUMBER() OVER (PARTITION BY login_id ORDER BY geldig_vanaf_ts DESC) AS rijnr
275+
FROM wh.login_wachtwoord
276+
) AS l
277+
WHERE rijnr = _aantal_versies
278+
) AS d -- Alleen de _aantal_versies-de rij bewaren; deze datum is het afkap-punt
279+
WHERE lw.login_id = d.login_id AND
280+
lw.geldig_vanaf_ts < d.geldig_vanaf_ts /* _aantal_versies = 5, dus datums verwijderen ouder dan de 5e */
281+
;
282+
283+
RETURN NEW;
284+
END;
285+
$BODY$
286+
LANGUAGE plpgsql;
287+
288+
ALTER FUNCTION wh.fnc_prune_pw_history() OWNER TO dwh_owner;
289+
290+
CREATE TRIGGER trg_fnc_prune_pw_history
291+
AFTER INSERT
292+
ON wh.login_wachtwoord
293+
EXECUTE FUNCTION wh.fnc_prune_pw_history();

0 commit comments

Comments
 (0)