Update ACL\Login class with _GET/_POST login parameter
loginUserId parameter in _GET or _POST for direct login without username and password. This can be secured by: - must login after x days from set loginUserId on - can only login with loginUserId in given time range - flag lock loginUserId
This commit is contained in:
@@ -5,6 +5,7 @@ function/set_edit_generic.sql
|
||||
function/edit_access_set_uid.sql
|
||||
function/edit_group_set_uid.sql
|
||||
function/edit_log_partition_insert.sql
|
||||
function/edit_user_set_login_user_id_set_date.sql
|
||||
# generic tables
|
||||
table/edit_temp_files.sql
|
||||
table/edit_generic.sql
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
-- create random string with length X
|
||||
|
||||
CREATE FUNCTION random_string(randomLength int)
|
||||
RETURNS text AS $$
|
||||
RETURNS text AS
|
||||
$$
|
||||
SELECT array_to_string(
|
||||
ARRAY(
|
||||
SELECT substring(
|
||||
@@ -14,53 +15,58 @@ SELECT array_to_string(
|
||||
),
|
||||
''
|
||||
)
|
||||
$$ LANGUAGE SQL
|
||||
$$
|
||||
LANGUAGE SQL
|
||||
RETURNS NULL ON NULL INPUT
|
||||
VOLATILE; -- LEAKPROOF;-- END: function/random_string.sql
|
||||
VOLATILE; -- LEAKPROOF;
|
||||
-- END: function/random_string.sql
|
||||
-- START: function/set_edit_generic.sql
|
||||
-- adds the created or updated date tags
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_edit_generic() RETURNS TRIGGER AS '
|
||||
DECLARE
|
||||
random_length INT = 12; -- that should be long enough
|
||||
BEGIN
|
||||
IF TG_OP = ''INSERT'' THEN
|
||||
NEW.date_created := ''now'';
|
||||
NEW.cuid := random_string(random_length);
|
||||
ELSIF TG_OP = ''UPDATE'' THEN
|
||||
NEW.date_updated := ''now'';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
' LANGUAGE 'plpgsql';
|
||||
CREATE OR REPLACE FUNCTION set_edit_generic()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
random_length INT = 12; -- that should be long enough
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
NEW.date_created := 'now';
|
||||
NEW.cuid := random_string(random_length);
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
NEW.date_updated := 'now';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/set_edit_generic.sql
|
||||
-- START: function/edit_access_set_uid.sql
|
||||
-- add uid add for edit_access table
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_edit_access_uid() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_access t WHERE edit_access_id = NEW.edit_access_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_access t WHERE edit_access_id = NEW.edit_access_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/edit_access_set_uid.sql
|
||||
@@ -69,28 +75,28 @@ $$
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_edit_group_uid() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_group t WHERE edit_group_id = NEW.edit_group_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_group t WHERE edit_group_id = NEW.edit_group_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/edit_group_set_uid.sql
|
||||
@@ -246,6 +252,32 @@ END
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/edit_log_partition_insert.sql
|
||||
-- START: function/edit_user_set_login_user_id_set_date.sql
|
||||
-- set edit user login_user_id_set_date if login_user_id is set
|
||||
-- NOW() if not empty
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_login_user_id_set_date()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
-- if new is not null/empty
|
||||
-- and old one is null or old one different new one
|
||||
-- set NOW()
|
||||
-- if new one is NULL
|
||||
-- set NULL
|
||||
IF
|
||||
NEW.login_user_id IS NOT NULL AND NEW.login_user_id <> '' AND
|
||||
(OLD.login_user_id IS NULL OR NEW.login_user_id <> OLD.login_user_id)
|
||||
THEN
|
||||
NEW.login_user_id_set_date = NOW();
|
||||
ELSIF NEW.login_user_id IS NULL OR NEW.login_user_id = '' THEN
|
||||
NEW.login_user_id_set_date = NULL;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/edit_user_set_login_user_id_set_date.sql
|
||||
-- START: table/edit_temp_files.sql
|
||||
-- AUTHOR: Clemens Schwaighofer
|
||||
-- DATE: 2005/07/08
|
||||
@@ -526,34 +558,80 @@ CREATE TABLE edit_user (
|
||||
FOREIGN KEY (edit_scheme_id) REFERENCES edit_scheme (edit_scheme_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
edit_access_right_id INT NOT NULL,
|
||||
FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
enabled SMALLINT NOT NULL DEFAULT 0,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0,
|
||||
-- username/password
|
||||
username VARCHAR UNIQUE,
|
||||
password VARCHAR,
|
||||
-- name block
|
||||
first_name VARCHAR,
|
||||
last_name VARCHAR,
|
||||
first_name_furigana VARCHAR,
|
||||
last_name_furigana VARCHAR,
|
||||
-- email
|
||||
email VARCHAR,
|
||||
-- eanbled/deleted flag
|
||||
enabled SMALLINT NOT NULL DEFAULT 0,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0,
|
||||
-- general flags
|
||||
strict SMALLINT DEFAULT 0,
|
||||
locked SMALLINT DEFAULT 0,
|
||||
protected SMALLINT NOT NULL DEFAULT 0,
|
||||
-- legacy, debug flags
|
||||
debug SMALLINT NOT NULL DEFAULT 0,
|
||||
db_debug SMALLINT NOT NULL DEFAULT 0,
|
||||
email VARCHAR,
|
||||
protected SMALLINT NOT NULL DEFAULT 0,
|
||||
-- is admin user
|
||||
admin SMALLINT NOT NULL DEFAULT 0,
|
||||
-- last login log
|
||||
last_login TIMESTAMP WITHOUT TIME ZONE,
|
||||
-- login error
|
||||
login_error_count INT DEFAULT 0,
|
||||
login_error_date_last TIMESTAMP WITHOUT TIME ZONE,
|
||||
login_error_date_first TIMESTAMP WITHOUT TIME ZONE,
|
||||
strict SMALLINT DEFAULT 0,
|
||||
locked SMALLINT DEFAULT 0,
|
||||
-- time locked
|
||||
lock_until TIMESTAMP WITHOUT TIME ZONE,
|
||||
lock_after TIMESTAMP WITHOUT TIME ZONE,
|
||||
-- password change
|
||||
password_change_date TIMESTAMP WITHOUT TIME ZONE, -- only when password is first set or changed
|
||||
password_change_interval INTERVAL, -- null if no change is needed, or d/m/y time interval
|
||||
password_reset_time TIMESTAMP WITHOUT TIME ZONE, -- when the password reset was requested
|
||||
password_reset_uid VARCHAR, -- the uid to access the password reset page
|
||||
-- _GET login id for direct login
|
||||
login_user_id VARCHAR, -- the login uid, at least 32 chars
|
||||
login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE, -- when above uid was set
|
||||
login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE, -- if set, from when the above uid is valid
|
||||
login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE, -- if set, until when the above uid is valid
|
||||
login_user_id_revalidate_after INTERVAL DEFAULT '0 days', -- user must login to revalidated login id after set days, 0 for forever
|
||||
login_user_id_locked SMALLINT DEFAULT 0, -- lock for login user id, but still allow normal login
|
||||
-- additional ACL json block
|
||||
additional_acl JSONB -- additional ACL as JSON string (can be set by other pages)
|
||||
) INHERITS (edit_generic) WITHOUT OIDS;
|
||||
|
||||
COMMENT ON COLUMN edit_user.username IS 'Login username, must set';
|
||||
COMMENT ON COLUMN edit_user.password IS 'Login password, must set';
|
||||
COMMENT ON COLUMN edit_user.enabled IS 'Login is enabled (master switch)';
|
||||
COMMENT ON COLUMN edit_user.deleted IS 'Login is deleted (master switch), overrides all other';
|
||||
COMMENT ON COLUMN edit_user.strict IS 'If too many failed logins user will be locked, default off';
|
||||
COMMENT ON COLUMN edit_user.locked IS 'Locked from too many wrong password logins';
|
||||
COMMENT ON COLUMN edit_user.protected IS 'User can only be chnaged by admin user';
|
||||
COMMENT ON COLUMN edit_user.debug IS 'Turn debug flag on (legacy)';
|
||||
COMMENT ON COLUMN edit_user.db_debug IS 'Turn DB debug flag on (legacy)';
|
||||
COMMENT ON COLUMN edit_user.admin IS 'If set, this user is SUPER admin';
|
||||
COMMENT ON COLUMN edit_user.last_login IS 'Last succesfull login tiemstamp';
|
||||
COMMENT ON COLUMN edit_user.login_error_count IS 'Number of failed logins, reset on successful login';
|
||||
COMMENT ON COLUMN edit_user.login_error_date_last IS 'Last login error date';
|
||||
COMMENT ON COLUMN edit_user.login_error_date_first IS 'First login error date, reset on successfull login';
|
||||
COMMENT ON COLUMN edit_user.lock_until IS 'Account is locked until this date, <';
|
||||
COMMENT ON COLUMN edit_user.lock_after IS 'Account is locked after this date, >';
|
||||
COMMENT ON COLUMN edit_user.password_change_date IS 'Password was changed on';
|
||||
COMMENT ON COLUMN edit_user.password_change_interval IS 'After how many days the password has to be changed';
|
||||
COMMENT ON COLUMN edit_user.password_reset_time IS 'When the password reset was requested. For reset page uid valid check';
|
||||
COMMENT ON COLUMN edit_user.password_reset_uid IS 'Password reset page uid';
|
||||
COMMENT ON COLUMN edit_user.password_reset_uid IS 'Password reset page uid, one time, invalid after reset successful or time out';
|
||||
COMMENT ON COLUMN edit_user.login_user_id IS 'Min 32 character UID to be used to login without password. Via GET/POST parameter';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_set_date IS 'login id was set at what date';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_valid_from IS 'login id is valid from this date, >=';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_valid_until IS 'login id is valid until this date, <=';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_revalidate_after IS 'If set to a number greater 0 then user must login after given amount of days to revalidate, set to 0 for valid forver';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_locked IS 'A separte lock flag for login id, user can still login normal';
|
||||
COMMENT ON COLUMN edit_user.additional_acl IS 'Additional Access Control List stored in JSON format';
|
||||
-- END: table/edit_user.sql
|
||||
-- START: table/edit_log.sql
|
||||
-- AUTHOR: Clemens Schwaighofer
|
||||
@@ -774,6 +852,11 @@ FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
|
||||
CREATE TRIGGER trg_edit_user
|
||||
BEFORE INSERT OR UPDATE ON edit_user
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
|
||||
|
||||
-- DROP TRIGGER IF EXISTS trg_edit_user_set_login_user_id_set_date ON edit_user;
|
||||
CREATE TRIGGER trg_edit_user_set_login_user_id_set_date
|
||||
BEFORE INSERT OR UPDATE ON edit_user
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_login_user_id_set_date();
|
||||
-- END: trigger/trg_edit_user.sql
|
||||
-- START: trigger/trg_edit_visible_group.sql
|
||||
-- DROP TRIGGER IF EXISTS trg_edit_visible_group ON edit_visible_group;
|
||||
|
||||
@@ -2,27 +2,27 @@
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_edit_access_uid() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_access t WHERE edit_access_id = NEW.edit_access_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_access t WHERE edit_access_id = NEW.edit_access_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
|
||||
@@ -2,27 +2,27 @@
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_edit_group_uid() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_group t WHERE edit_group_id = NEW.edit_group_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_group t WHERE edit_group_id = NEW.edit_group_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
-- set edit user login_user_id_set_date if login_user_id is set
|
||||
-- NOW() if not empty
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_login_user_id_set_date()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
-- if new is not null/empty
|
||||
-- and old one is null or old one different new one
|
||||
-- set NOW()
|
||||
-- if new one is NULL
|
||||
-- set NULL
|
||||
IF
|
||||
NEW.login_user_id IS NOT NULL AND NEW.login_user_id <> '' AND
|
||||
(OLD.login_user_id IS NULL OR NEW.login_user_id <> OLD.login_user_id)
|
||||
THEN
|
||||
NEW.login_user_id_set_date = NOW();
|
||||
ELSIF NEW.login_user_id IS NULL OR NEW.login_user_id = '' THEN
|
||||
NEW.login_user_id_set_date = NULL;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
@@ -1,7 +1,8 @@
|
||||
-- create random string with length X
|
||||
|
||||
CREATE FUNCTION random_string(randomLength int)
|
||||
RETURNS text AS $$
|
||||
RETURNS text AS
|
||||
$$
|
||||
SELECT array_to_string(
|
||||
ARRAY(
|
||||
SELECT substring(
|
||||
@@ -13,6 +14,7 @@ SELECT array_to_string(
|
||||
),
|
||||
''
|
||||
)
|
||||
$$ LANGUAGE SQL
|
||||
$$
|
||||
LANGUAGE SQL
|
||||
RETURNS NULL ON NULL INPUT
|
||||
VOLATILE; -- LEAKPROOF;
|
||||
VOLATILE; -- LEAKPROOF;
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
-- adds the created or updated date tags
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_date() RETURNS TRIGGER AS '
|
||||
BEGIN
|
||||
IF TG_OP = ''INSERT'' THEN
|
||||
NEW.date_created := ''now'';
|
||||
ELSIF TG_OP = ''UPDATE'' THEN
|
||||
NEW.date_updated := ''now'';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
' LANGUAGE 'plpgsql';
|
||||
CREATE OR REPLACE FUNCTION set_date()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
NEW.date_created := 'now';
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
NEW.date_updated := 'now';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
-- adds the created or updated date tags
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_edit_generic() RETURNS TRIGGER AS '
|
||||
DECLARE
|
||||
random_length INT = 12; -- that should be long enough
|
||||
BEGIN
|
||||
IF TG_OP = ''INSERT'' THEN
|
||||
NEW.date_created := ''now'';
|
||||
NEW.cuid := random_string(random_length);
|
||||
ELSIF TG_OP = ''UPDATE'' THEN
|
||||
NEW.date_updated := ''now'';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
' LANGUAGE 'plpgsql';
|
||||
CREATE OR REPLACE FUNCTION set_edit_generic()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
random_length INT = 12; -- that should be long enough
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
NEW.date_created := 'now';
|
||||
NEW.cuid := random_string(random_length);
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
NEW.date_updated := 'now';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
-- set generic with date and uid combined
|
||||
-- don't use with set_generic/set_uid together
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_generic() RETURNS TRIGGER AS '
|
||||
DECLARE
|
||||
random_length INT = 32; -- long for massive data
|
||||
BEGIN
|
||||
IF TG_OP = ''INSERT'' THEN
|
||||
NEW.date_created := ''now'';
|
||||
IF NEW.uid IS NULL THEN
|
||||
NEW.uid := random_string(random_length);
|
||||
END IF;
|
||||
ELSIF TG_OP = ''UPDATE'' THEN
|
||||
NEW.date_updated := ''now'';
|
||||
CREATE OR REPLACE FUNCTION set_generic()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
random_length INT = 32; -- long for massive data
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
NEW.date_created := 'now';
|
||||
IF NEW.uid IS NULL THEN
|
||||
NEW.uid := random_string(random_length);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
' LANGUAGE 'plpgsql';
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
NEW.date_updated := 'now';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
-- adds the created or updated date tags
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_uid() RETURNS TRIGGER AS '
|
||||
DECLARE
|
||||
random_length INT = 32; -- that should be long enough
|
||||
BEGIN
|
||||
IF TG_OP = ''INSERT'' THEN
|
||||
NEW.uid := random_string(random_length);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
' LANGUAGE 'plpgsql';
|
||||
CREATE OR REPLACE FUNCTION set_uid()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
random_length INT = 32; -- that should be long enough
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
NEW.uid := random_string(random_length);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
|
||||
-- OLD, DEPRECATED, use set_generic.sql
|
||||
|
||||
-- CREATE OR REPLACE FUNCTION set_generic() RETURNS TRIGGER AS '
|
||||
-- BEGIN
|
||||
-- IF TG_OP = ''INSERT'' THEN
|
||||
-- NEW.date_created := clock_timestamp();
|
||||
-- NEW.user_created := current_user;
|
||||
-- ELSIF TG_OP = ''UPDATE'' THEN
|
||||
-- NEW.date_updated := clock_timestamp();
|
||||
-- NEW.user_updated := current_user;
|
||||
-- END IF;
|
||||
-- RETURN NEW;
|
||||
-- END;
|
||||
-- ' LANGUAGE 'plpgsql';
|
||||
-- CREATE OR REPLACE FUNCTION set_generic()
|
||||
-- RETURNS TRIGGER AS
|
||||
-- $$
|
||||
-- BEGIN
|
||||
-- IF TG_OP = 'INSERT' THEN
|
||||
-- NEW.date_created := clock_timestamp();
|
||||
-- NEW.user_created := current_user;
|
||||
-- ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- NEW.date_updated := clock_timestamp();
|
||||
-- NEW.user_updated := current_user;
|
||||
-- END IF;
|
||||
-- RETURN NEW;
|
||||
-- END;
|
||||
-- $$
|
||||
-- LANGUAGE 'plpgsql';
|
||||
|
||||
@@ -18,31 +18,77 @@ CREATE TABLE edit_user (
|
||||
FOREIGN KEY (edit_scheme_id) REFERENCES edit_scheme (edit_scheme_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
edit_access_right_id INT NOT NULL,
|
||||
FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
enabled SMALLINT NOT NULL DEFAULT 0,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0,
|
||||
-- username/password
|
||||
username VARCHAR UNIQUE,
|
||||
password VARCHAR,
|
||||
-- name block
|
||||
first_name VARCHAR,
|
||||
last_name VARCHAR,
|
||||
first_name_furigana VARCHAR,
|
||||
last_name_furigana VARCHAR,
|
||||
-- email
|
||||
email VARCHAR,
|
||||
-- eanbled/deleted flag
|
||||
enabled SMALLINT NOT NULL DEFAULT 0,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0,
|
||||
-- general flags
|
||||
strict SMALLINT DEFAULT 0,
|
||||
locked SMALLINT DEFAULT 0,
|
||||
protected SMALLINT NOT NULL DEFAULT 0,
|
||||
-- legacy, debug flags
|
||||
debug SMALLINT NOT NULL DEFAULT 0,
|
||||
db_debug SMALLINT NOT NULL DEFAULT 0,
|
||||
email VARCHAR,
|
||||
protected SMALLINT NOT NULL DEFAULT 0,
|
||||
-- is admin user
|
||||
admin SMALLINT NOT NULL DEFAULT 0,
|
||||
-- last login log
|
||||
last_login TIMESTAMP WITHOUT TIME ZONE,
|
||||
-- login error
|
||||
login_error_count INT DEFAULT 0,
|
||||
login_error_date_last TIMESTAMP WITHOUT TIME ZONE,
|
||||
login_error_date_first TIMESTAMP WITHOUT TIME ZONE,
|
||||
strict SMALLINT DEFAULT 0,
|
||||
locked SMALLINT DEFAULT 0,
|
||||
-- time locked
|
||||
lock_until TIMESTAMP WITHOUT TIME ZONE,
|
||||
lock_after TIMESTAMP WITHOUT TIME ZONE,
|
||||
-- password change
|
||||
password_change_date TIMESTAMP WITHOUT TIME ZONE, -- only when password is first set or changed
|
||||
password_change_interval INTERVAL, -- null if no change is needed, or d/m/y time interval
|
||||
password_reset_time TIMESTAMP WITHOUT TIME ZONE, -- when the password reset was requested
|
||||
password_reset_uid VARCHAR, -- the uid to access the password reset page
|
||||
-- _GET login id for direct login
|
||||
login_user_id VARCHAR, -- the login uid, at least 32 chars
|
||||
login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE, -- when above uid was set
|
||||
login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE, -- if set, from when the above uid is valid
|
||||
login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE, -- if set, until when the above uid is valid
|
||||
login_user_id_revalidate_after INTERVAL DEFAULT '0 days', -- user must login to revalidated login id after set days, 0 for forever
|
||||
login_user_id_locked SMALLINT DEFAULT 0, -- lock for login user id, but still allow normal login
|
||||
-- additional ACL json block
|
||||
additional_acl JSONB -- additional ACL as JSON string (can be set by other pages)
|
||||
) INHERITS (edit_generic) WITHOUT OIDS;
|
||||
|
||||
COMMENT ON COLUMN edit_user.username IS 'Login username, must set';
|
||||
COMMENT ON COLUMN edit_user.password IS 'Login password, must set';
|
||||
COMMENT ON COLUMN edit_user.enabled IS 'Login is enabled (master switch)';
|
||||
COMMENT ON COLUMN edit_user.deleted IS 'Login is deleted (master switch), overrides all other';
|
||||
COMMENT ON COLUMN edit_user.strict IS 'If too many failed logins user will be locked, default off';
|
||||
COMMENT ON COLUMN edit_user.locked IS 'Locked from too many wrong password logins';
|
||||
COMMENT ON COLUMN edit_user.protected IS 'User can only be chnaged by admin user';
|
||||
COMMENT ON COLUMN edit_user.debug IS 'Turn debug flag on (legacy)';
|
||||
COMMENT ON COLUMN edit_user.db_debug IS 'Turn DB debug flag on (legacy)';
|
||||
COMMENT ON COLUMN edit_user.admin IS 'If set, this user is SUPER admin';
|
||||
COMMENT ON COLUMN edit_user.last_login IS 'Last succesfull login tiemstamp';
|
||||
COMMENT ON COLUMN edit_user.login_error_count IS 'Number of failed logins, reset on successful login';
|
||||
COMMENT ON COLUMN edit_user.login_error_date_last IS 'Last login error date';
|
||||
COMMENT ON COLUMN edit_user.login_error_date_first IS 'First login error date, reset on successfull login';
|
||||
COMMENT ON COLUMN edit_user.lock_until IS 'Account is locked until this date, <';
|
||||
COMMENT ON COLUMN edit_user.lock_after IS 'Account is locked after this date, >';
|
||||
COMMENT ON COLUMN edit_user.password_change_date IS 'Password was changed on';
|
||||
COMMENT ON COLUMN edit_user.password_change_interval IS 'After how many days the password has to be changed';
|
||||
COMMENT ON COLUMN edit_user.password_reset_time IS 'When the password reset was requested. For reset page uid valid check';
|
||||
COMMENT ON COLUMN edit_user.password_reset_uid IS 'Password reset page uid';
|
||||
COMMENT ON COLUMN edit_user.password_reset_uid IS 'Password reset page uid, one time, invalid after reset successful or time out';
|
||||
COMMENT ON COLUMN edit_user.login_user_id IS 'Min 32 character UID to be used to login without password. Via GET/POST parameter';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_set_date IS 'login id was set at what date';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_valid_from IS 'login id is valid from this date, >=';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_valid_until IS 'login id is valid until this date, <=';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_revalidate_after IS 'If set to a number greater 0 then user must login after given amount of days to revalidate, set to 0 for valid forver';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_locked IS 'A separte lock flag for login id, user can still login normal';
|
||||
COMMENT ON COLUMN edit_user.additional_acl IS 'Additional Access Control List stored in JSON format';
|
||||
|
||||
@@ -2,3 +2,8 @@
|
||||
CREATE TRIGGER trg_edit_user
|
||||
BEFORE INSERT OR UPDATE ON edit_user
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
|
||||
|
||||
-- DROP TRIGGER IF EXISTS trg_edit_user_set_login_user_id_set_date ON edit_user;
|
||||
CREATE TRIGGER trg_edit_user_set_login_user_id_set_date
|
||||
BEFORE INSERT OR UPDATE ON edit_user
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_login_user_id_set_date();
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
-- 2022/6/17 update edit_user with login uid
|
||||
|
||||
-- the login uid, at least 32 chars
|
||||
ALTER TABLE edit_user ADD login_user_id VARCHAR;
|
||||
-- when above uid was set
|
||||
ALTER TABLE edit_user ADD login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE;
|
||||
-- if set, from/until when the above uid is valid
|
||||
ALTER TABLE edit_user ADD login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE;
|
||||
ALTER TABLE edit_user ADD login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE;
|
||||
-- user must login to revalidated login id after set days, 0 for forever
|
||||
ALTER TABLE edit_user ADD login_user_id_revalidate_after INTERVAL NOT NULL DEFAULT '0 days';
|
||||
-- lock for login user id, but still allow normal login
|
||||
ALTER TABLE edit_user ADD login_user_id_locked SMALLINT NOT NULL DEFAULT 0;
|
||||
|
||||
-- disable login before date
|
||||
ALTER TABLE edit_user ADD lock_until TIMESTAMP WITHOUT TIME ZONE;
|
||||
-- disable login after date
|
||||
ALTER TABLE edit_user ADD lock_after TIMESTAMP WITHOUT TIME ZONE;
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_login_user_id_set_date()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
-- if new is not null/empty
|
||||
-- and old one is null or old one different new one
|
||||
-- set NOW()
|
||||
-- if new one is NULL
|
||||
-- set NULL
|
||||
IF
|
||||
NEW.login_user_id IS NOT NULL AND NEW.login_user_id <> '' AND
|
||||
(OLD.login_user_id IS NULL OR NEW.login_user_id <> OLD.login_user_id)
|
||||
THEN
|
||||
NEW.login_user_id_set_date = NOW();
|
||||
ELSIF NEW.login_user_id IS NULL OR NEW.login_user_id = '' THEN
|
||||
NEW.login_user_id_set_date = NULL;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
|
||||
|
||||
CREATE TRIGGER trg_edit_user_set_login_user_id_set_date
|
||||
BEFORE INSERT OR UPDATE ON edit_user
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_login_user_id_set_date();
|
||||
|
||||
-- __END__
|
||||
@@ -16,8 +16,6 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
{
|
||||
private static $db;
|
||||
private static $log;
|
||||
/** @var \CoreLibs\Create\Session&MockObject */
|
||||
private static $session;
|
||||
|
||||
/**
|
||||
* start DB conneciton, setup DB, etc
|
||||
@@ -101,6 +99,8 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'Cannot find edit_user table in ACL\Login database for testing'
|
||||
);
|
||||
}
|
||||
// always disable max query calls
|
||||
self::$db->dbSetMaxQueryCall(-1);
|
||||
// insert additional content for testing (locked user, etc)
|
||||
$queries = [
|
||||
"INSERT INTO edit_access_data "
|
||||
@@ -158,6 +158,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
public function loginProvider(): array
|
||||
{
|
||||
// 0: mock settings/override flag settings
|
||||
// 2: get array IN
|
||||
// 1: post array IN
|
||||
// login_login, login_username, login_password, login_logout
|
||||
// change_password, pw_username, pw_old_password, pw_new_password,
|
||||
@@ -174,6 +175,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 0,
|
||||
@@ -191,6 +193,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 0,
|
||||
@@ -213,6 +216,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 0,
|
||||
@@ -230,6 +234,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'page_name' => 'edit_users.php',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'EUID' => 1,
|
||||
],
|
||||
@@ -246,6 +251,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'page_access' => 'list',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'EUID' => 1,
|
||||
'USER_NAME' => '',
|
||||
@@ -288,6 +294,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => '',
|
||||
@@ -308,6 +315,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => '',
|
||||
@@ -328,6 +336,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'abc',
|
||||
@@ -348,6 +357,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'abc',
|
||||
@@ -371,6 +381,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
@@ -387,6 +398,31 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
. 'Login Failed - Wrong Username or Password'
|
||||
]
|
||||
],
|
||||
// login: ok (but deleted)
|
||||
'login: ok, but deleted' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_deleted' => true
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
'login_password' => 'admin',
|
||||
],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 106,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - User is deleted</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - User is deleted'
|
||||
]
|
||||
],
|
||||
// login: ok (but not enabled)
|
||||
'login: ok, but not enabled' => [
|
||||
[
|
||||
@@ -396,6 +432,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'page_access' => 'list',
|
||||
'test_enabled' => true
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
@@ -420,6 +457,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'page_access' => 'list',
|
||||
'test_locked' => true
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
@@ -446,6 +484,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'max_login_error_count' => 2,
|
||||
'test_locked_strict' => true,
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
@@ -458,6 +497,136 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'login_error' => 105,
|
||||
]
|
||||
],
|
||||
// login ok, but in locked period (until)
|
||||
'login: ok, but locked period (until:on)' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_locked_period_until' => 'on'
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
'login_password' => 'admin',
|
||||
],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 107,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - User in locked via date period</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - User in locked via date period'
|
||||
]
|
||||
],
|
||||
// login ok, but in locked period (until)
|
||||
'login: ok, but locked period (until:off)' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'edit_access_uid' => 'AdminAccess',
|
||||
'edit_access_data' => 'test',
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_locked_period_until' => 'off'
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
'login_password' => 'admin',
|
||||
],
|
||||
[],
|
||||
0,
|
||||
[
|
||||
'login_error' => 0,
|
||||
'admin_flag' => true,
|
||||
'check_access' => true,
|
||||
'check_access_id' => 1,
|
||||
'check_access_data' => 'value',
|
||||
'base_access' => true,
|
||||
'page_access' => true,
|
||||
]
|
||||
],
|
||||
// login ok, but in locked period (after)
|
||||
'login: ok, but locked period (after:on)' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_locked_period_after' => 'on'
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
'login_password' => 'admin',
|
||||
],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 107,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - User in locked via date period</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - User in locked via date period'
|
||||
]
|
||||
],
|
||||
// login ok, but in locked period (until, after)
|
||||
'login: ok, but locked period (until:on, after:on)' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_locked_period_until' => 'on',
|
||||
'test_locked_period_after' => 'on'
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
'login_password' => 'admin',
|
||||
],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 107,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - User in locked via date period</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - User in locked via date period'
|
||||
]
|
||||
],
|
||||
// login ok, but login user id locked
|
||||
'login: ok, but login user id locked' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id_locked' => true
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
'login_password' => 'admin',
|
||||
],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 108,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - User is locked via Login User ID</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - User is locked via Login User ID'
|
||||
]
|
||||
],
|
||||
// login: ok
|
||||
'login: ok' => [
|
||||
[
|
||||
@@ -468,6 +637,148 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
],
|
||||
[],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
'login_password' => 'admin',
|
||||
],
|
||||
[],
|
||||
0,
|
||||
[
|
||||
'login_error' => 0,
|
||||
'admin_flag' => true,
|
||||
'check_access' => true,
|
||||
'check_access_id' => 1,
|
||||
'check_access_data' => 'value',
|
||||
'base_access' => true,
|
||||
'page_access' => true,
|
||||
]
|
||||
],
|
||||
// login check via _GET loginUserId
|
||||
'login: ok, _GET loginUserId' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'edit_access_uid' => 'AdminAccess',
|
||||
'edit_access_data' => 'test',
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
0,
|
||||
[
|
||||
'login_error' => 0,
|
||||
'admin_flag' => true,
|
||||
'check_access' => true,
|
||||
'check_access_id' => 1,
|
||||
'check_access_data' => 'value',
|
||||
'base_access' => true,
|
||||
'page_access' => true,
|
||||
]
|
||||
],
|
||||
// login check via _POST loginUserId
|
||||
'login: ok, _POST loginUserId' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'edit_access_uid' => 'AdminAccess',
|
||||
'edit_access_data' => 'test',
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[],
|
||||
[
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[],
|
||||
0,
|
||||
[
|
||||
'login_error' => 0,
|
||||
'admin_flag' => true,
|
||||
'check_access' => true,
|
||||
'check_access_id' => 1,
|
||||
'check_access_data' => 'value',
|
||||
'base_access' => true,
|
||||
'page_access' => true,
|
||||
]
|
||||
],
|
||||
// login: wrong GET loginUserId
|
||||
'login: ok, illegal chars in _GET loginUserId' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'edit_access_uid' => 'AdminAccess',
|
||||
'edit_access_data' => 'test',
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG'
|
||||
],
|
||||
[
|
||||
'loginUserId' => '123$%_/45678¥\-^9~~0$AB&CDEFG',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
0,
|
||||
[
|
||||
'login_error' => 0,
|
||||
'admin_flag' => true,
|
||||
'check_access' => true,
|
||||
'check_access_id' => 1,
|
||||
'check_access_data' => 'value',
|
||||
'base_access' => true,
|
||||
'page_access' => true,
|
||||
]
|
||||
],
|
||||
'login: not matching _GET loginUserId' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG'
|
||||
],
|
||||
[
|
||||
'loginUserId' => 'ABC'
|
||||
],
|
||||
[],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 1010,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - Wrong Username or Password</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - Wrong Username or Password'
|
||||
]
|
||||
],
|
||||
// login ok with both _GET loginUserId and _POST login username/password
|
||||
'login: ok, _GET loginUserId AND login post user data' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'edit_access_uid' => 'AdminAccess',
|
||||
'edit_access_data' => 'test',
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
@@ -485,9 +796,208 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'page_access' => true,
|
||||
]
|
||||
],
|
||||
// login with invalid loginUserId but valid username/password
|
||||
'login: ok, bad _GET loginUserId AND good login post user data' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'edit_access_uid' => 'AdminAccess',
|
||||
'edit_access_data' => 'test',
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'loginUserId' => 'ABCS',
|
||||
],
|
||||
[
|
||||
'login_login' => 'Login',
|
||||
'login_username' => 'admin',
|
||||
'login_password' => 'admin',
|
||||
],
|
||||
[],
|
||||
0,
|
||||
[
|
||||
'login_error' => 0,
|
||||
'admin_flag' => true,
|
||||
'check_access' => true,
|
||||
'check_access_id' => 1,
|
||||
'check_access_data' => 'value',
|
||||
'base_access' => true,
|
||||
'page_access' => true,
|
||||
]
|
||||
],
|
||||
// loginUserId check with revalidate on/off
|
||||
'login: ok, but revalidate trigger, _GET loginUserId' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id_revalidate_after' => 'on',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 1101,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - Login User ID must be validated</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - Login User ID must be validated'
|
||||
]
|
||||
],
|
||||
// loginUserId check with revalidate on/off
|
||||
'login: ok, revalidate set (outside), _GET loginUserId' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'edit_access_uid' => 'AdminAccess',
|
||||
'edit_access_data' => 'test',
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id_revalidate_after' => 'off',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
0,
|
||||
[
|
||||
'login_error' => 0,
|
||||
'admin_flag' => true,
|
||||
'check_access' => true,
|
||||
'check_access_id' => 1,
|
||||
'check_access_data' => 'value',
|
||||
'base_access' => true,
|
||||
'page_access' => true,
|
||||
]
|
||||
],
|
||||
// loginUserId check with active time from only
|
||||
'login: ok, _GET loginUserId, but outside valid (from:on) ' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id_valid_from' => 'on',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 1102,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - Login User ID is outside valid date range</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - Login User ID is outside valid date range'
|
||||
]
|
||||
],
|
||||
// loginUserId check with inactive time from only
|
||||
'login: ok, _GET loginUserId, but outside valid (from:off) ' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'edit_access_uid' => 'AdminAccess',
|
||||
'edit_access_data' => 'test',
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id_valid_from' => 'off',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
0,
|
||||
[
|
||||
'login_error' => 0,
|
||||
'admin_flag' => true,
|
||||
'check_access' => true,
|
||||
'check_access_id' => 1,
|
||||
'check_access_data' => 'value',
|
||||
'base_access' => true,
|
||||
'page_access' => true,
|
||||
]
|
||||
],
|
||||
// loginUserId check with active time until only
|
||||
'login: ok, _GET loginUserId, but outside valid (until:on) ' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id_valid_until' => 'on',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 1102,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - Login User ID is outside valid date range</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - Login User ID is outside valid date range'
|
||||
]
|
||||
],
|
||||
// loginUserId check with active time from/until
|
||||
'login: ok, _GET loginUserId, but outside valid (from:on,until:on) ' => [
|
||||
[
|
||||
'page_name' => 'edit_users.php',
|
||||
'edit_access_id' => 1,
|
||||
'base_access' => 'list',
|
||||
'page_access' => 'list',
|
||||
'test_login_user_id_valid_from' => 'on',
|
||||
'test_login_user_id_valid_until' => 'on',
|
||||
'test_login_user_id' => true,
|
||||
'test_username' => 'admin',
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[
|
||||
'loginUserId' => '1234567890ABCDEFG',
|
||||
],
|
||||
[],
|
||||
[],
|
||||
3000,
|
||||
[
|
||||
'login_error' => 1102,
|
||||
'error_string' => '<span style="color: red;">Fatal Error:</span> '
|
||||
. '<b>Login Failed - Login User ID is outside valid date range</b>',
|
||||
'error_string_text' => 'Fatal Error: '
|
||||
. 'Login Failed - Login User ID is outside valid date range'
|
||||
]
|
||||
],
|
||||
//
|
||||
// other:
|
||||
// login check edit access id of ID not null and not in array
|
||||
// login OK, but during action user gets disabled/deleted/etc
|
||||
];
|
||||
}
|
||||
|
||||
@@ -498,14 +1008,16 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
* @testdox ACL\Login Class tests [$_dataName]
|
||||
*
|
||||
* @param array<string,mixed> $mock_settings
|
||||
* @param array<string,string> $get
|
||||
* @param array<string,string> $post
|
||||
* @param array<string,mixed> $session
|
||||
* @param int $error
|
||||
* @param array<string,mixed> $expected
|
||||
* @return void
|
||||
*/
|
||||
public function testACLLogin(
|
||||
public function testACLLoginFlow(
|
||||
array $mock_settings,
|
||||
array $get,
|
||||
array $post,
|
||||
array $session,
|
||||
int $error,
|
||||
@@ -534,6 +1046,11 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
})
|
||||
);
|
||||
|
||||
// set _GET data
|
||||
foreach ($get as $get_var => $get_value) {
|
||||
$_GET[$get_var] = $get_value;
|
||||
}
|
||||
|
||||
// set _POST data
|
||||
foreach ($post as $post_var => $post_value) {
|
||||
$_POST[$post_var] = $post_value;
|
||||
@@ -574,6 +1091,47 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
. self::$db->dbEscapeLiteral($post['login_username'])
|
||||
);
|
||||
}
|
||||
if (!empty($mock_settings['test_deleted'])) {
|
||||
self::$db->dbExec(
|
||||
"UPDATE edit_user SET deleted = 1 WHERE LOWER(username) = "
|
||||
. self::$db->dbEscapeLiteral($post['login_username'])
|
||||
);
|
||||
}
|
||||
if (!empty($mock_settings['test_login_user_id_locked'])) {
|
||||
self::$db->dbExec(
|
||||
"UPDATE edit_user SET login_user_id_locked = 1 WHERE LOWER(username) = "
|
||||
. self::$db->dbEscapeLiteral($post['login_username'])
|
||||
);
|
||||
}
|
||||
if (
|
||||
!empty($mock_settings['test_locked_period_until']) ||
|
||||
!empty($mock_settings['test_locked_period_after'])
|
||||
) {
|
||||
$q_sub = '';
|
||||
if (!empty($mock_settings['test_locked_period_until'])) {
|
||||
if ($mock_settings['test_locked_period_until'] == 'on') {
|
||||
$q_sub .= "lock_until = NOW() + '1 day'::interval ";
|
||||
} elseif ($mock_settings['test_locked_period_until'] == 'off') {
|
||||
$q_sub .= "lock_until = NOW() - '1 day'::interval ";
|
||||
}
|
||||
}
|
||||
if (!empty($mock_settings['test_locked_period_after'])) {
|
||||
if (!empty($q_sub)) {
|
||||
$q_sub .= ", ";
|
||||
}
|
||||
if ($mock_settings['test_locked_period_after'] == 'on') {
|
||||
$q_sub .= "lock_after = NOW() - '1 day'::interval ";
|
||||
} elseif ($mock_settings['test_locked_period_after'] == 'off') {
|
||||
$q_sub .= "lock_after = NOW() + '1 day'::interval ";
|
||||
}
|
||||
}
|
||||
self::$db->dbExec(
|
||||
"UPDATE edit_user SET "
|
||||
. $q_sub
|
||||
. "WHERE LOWER(username) = "
|
||||
. self::$db->dbEscapeLiteral($post['login_username'])
|
||||
);
|
||||
}
|
||||
// test locked already
|
||||
if (!empty($mock_settings['test_locked'])) {
|
||||
self::$db->dbExec(
|
||||
@@ -635,6 +1193,62 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
// set correct password next locked login
|
||||
$_POST['login_password'] = $post['login_password'];
|
||||
}
|
||||
if (!empty($mock_settings['test_login_user_id'])) {
|
||||
self::$db->dbExec(
|
||||
"UPDATE edit_user SET "
|
||||
. "login_user_id_set_date = NOW(), "
|
||||
. "login_user_id = "
|
||||
. self::$db->dbEscapeLiteral($mock_settings['loginUserId'])
|
||||
. " "
|
||||
. "WHERE LOWER(username) = "
|
||||
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
|
||||
);
|
||||
}
|
||||
if (!empty($mock_settings['test_login_user_id_revalidate_after'])) {
|
||||
$q_sub = '';
|
||||
if ($mock_settings['test_login_user_id_revalidate_after'] == 'on') {
|
||||
$q_sub = "login_user_id_set_date = NOW() - '1 day'::interval, "
|
||||
. "login_user_id_revalidate_after = '1 day'::interval ";
|
||||
} else {
|
||||
$q_sub = "login_user_id_set_date = NOW(), "
|
||||
. "login_user_id_revalidate_after = '6 day'::interval ";
|
||||
}
|
||||
self::$db->dbExec(
|
||||
"UPDATE edit_user SET "
|
||||
. $q_sub
|
||||
. "WHERE LOWER(username) = "
|
||||
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
|
||||
);
|
||||
}
|
||||
if (
|
||||
!empty($mock_settings['test_login_user_id_valid_from']) ||
|
||||
!empty($mock_settings['test_login_user_id_valid_until'])
|
||||
) {
|
||||
$q_sub = '';
|
||||
if (!empty($mock_settings['test_login_user_id_valid_from'])) {
|
||||
if ($mock_settings['test_login_user_id_valid_from'] == 'on') {
|
||||
$q_sub .= "login_user_id_valid_from = NOW() + '1 day'::interval ";
|
||||
} elseif ($mock_settings['test_login_user_id_valid_from'] == 'off') {
|
||||
$q_sub .= "login_user_id_valid_from = NOW() - '1 day'::interval ";
|
||||
}
|
||||
}
|
||||
if (!empty($mock_settings['test_login_user_id_valid_until'])) {
|
||||
if (!empty($q_sub)) {
|
||||
$q_sub .= ", ";
|
||||
}
|
||||
if ($mock_settings['test_login_user_id_valid_until'] == 'on') {
|
||||
$q_sub .= "login_user_id_valid_until = NOW() - '1 day'::interval ";
|
||||
} elseif ($mock_settings['test_login_user_id_valid_until'] == 'off') {
|
||||
$q_sub .= "login_user_id_valid_until = NOW() + '1 day'::interval ";
|
||||
}
|
||||
}
|
||||
self::$db->dbExec(
|
||||
"UPDATE edit_user SET "
|
||||
. $q_sub
|
||||
. "WHERE LOWER(username) = "
|
||||
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
|
||||
);
|
||||
}
|
||||
|
||||
// run test
|
||||
try {
|
||||
@@ -734,6 +1348,13 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
$login_mock->loginGetAcl(),
|
||||
'Assert get acl is array'
|
||||
);
|
||||
// if loginUserId in _GET or _POST check that it is set
|
||||
if (!empty($get['loginUserId']) || !empty($post['loginUserId'])) {
|
||||
$this->assertNotEmpty(
|
||||
$login_mock->loginGetLoginUserId(),
|
||||
'Assert loginUserId is set'
|
||||
);
|
||||
}
|
||||
// TODO: detail match of ACL array (loginGetAcl)
|
||||
|
||||
// .. end with: loginLogoutUser
|
||||
@@ -840,6 +1461,35 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
// always check, even on error or not set
|
||||
if (!$login_mock->loginGetLoginUserIdUnclean()) {
|
||||
$this->assertEquals(
|
||||
$_GET['loginUserId'] ?? $_POST['loginUserId'] ?? '',
|
||||
$login_mock->loginGetLoginUserId(),
|
||||
'Assert loginUserId matches'
|
||||
);
|
||||
} else {
|
||||
$this->assertTrue(
|
||||
$login_mock->loginGetLoginUserIdUnclean(),
|
||||
'Assert loginUserId is unclear'
|
||||
);
|
||||
$this->assertNotEquals(
|
||||
$_GET['loginUserId'] ?? $_POST['loginUserId'] ?? '',
|
||||
$login_mock->loginGetLoginUserId(),
|
||||
'Assert loginUserId does not matche _GET/_POST'
|
||||
);
|
||||
}
|
||||
// check get/post login user id
|
||||
$this->assertEquals(
|
||||
(!empty($_GET['loginUserId']) ?
|
||||
'GET' :
|
||||
(!empty($_POST['loginUserId']) ?
|
||||
'POST' : '')
|
||||
),
|
||||
$login_mock->loginGetLoginUserIdSource(),
|
||||
'Assert loginUserId source matches'
|
||||
);
|
||||
|
||||
// enable user again if flag set
|
||||
if (!empty($mock_settings['test_enabled'])) {
|
||||
self::$db->dbExec(
|
||||
@@ -848,6 +1498,30 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
. self::$db->dbEscapeLiteral($post['login_username'])
|
||||
);
|
||||
}
|
||||
if (!empty($mock_settings['test_deleted'])) {
|
||||
self::$db->dbExec(
|
||||
"UPDATE edit_user SET deleted = 0 WHERE LOWER(username) = "
|
||||
. self::$db->dbEscapeLiteral($post['login_username'])
|
||||
);
|
||||
}
|
||||
if (!empty($mock_settings['test_login_user_id_locked'])) {
|
||||
self::$db->dbExec(
|
||||
"UPDATE edit_user SET login_user_id_locked = 0 WHERE LOWER(username) = "
|
||||
. self::$db->dbEscapeLiteral($post['login_username'])
|
||||
);
|
||||
}
|
||||
if (
|
||||
!empty($mock_settings['test_locked_period_until']) ||
|
||||
!empty($mock_settings['test_locked_period_after'])
|
||||
) {
|
||||
self::$db->dbExec(
|
||||
"UPDATE edit_user SET "
|
||||
. "lock_until = NULL, "
|
||||
. "lock_after = NULL "
|
||||
. "WHERE LOWER(username) = "
|
||||
. self::$db->dbEscapeLiteral($post['login_username'])
|
||||
);
|
||||
}
|
||||
// reset lock flag
|
||||
if (!empty($mock_settings['test_locked'])) {
|
||||
self::$db->dbExec(
|
||||
@@ -866,6 +1540,36 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
. self::$db->dbEscapeLiteral($post['login_username'])
|
||||
);
|
||||
}
|
||||
// if (!empty($mock_settings['test_login_user_id'])) {
|
||||
// self::$db->dbExec(
|
||||
// "UPDATE edit_user SET "
|
||||
// . "login_user_id = NULL, "
|
||||
// . "login_user_id_set_date = NULL "
|
||||
// . "WHERE LOWER(username) = "
|
||||
// . self::$db->dbEscapeLiteral($mock_settings['test_username'])
|
||||
// );
|
||||
// }
|
||||
// if (!empty($mock_settings['test_login_user_id_revalidate_after'])) {
|
||||
// self::$db->dbExec(
|
||||
// "UPDATE edit_user SET "
|
||||
// . "login_user_id_set_date = NULL, "
|
||||
// . "login_user_id_revalidate_after = NULL "
|
||||
// . "WHERE LOWER(username) = "
|
||||
// . self::$db->dbEscapeLiteral($mock_settings['test_username'])
|
||||
// );
|
||||
// }
|
||||
// if (
|
||||
// !empty($mock_settings['test_login_user_id_valid_from']) ||
|
||||
// !empty($mock_settings['test_login_user_id_valid_until'])
|
||||
// ) {
|
||||
// self::$db->dbExec(
|
||||
// "UPDATE edit_user SET "
|
||||
// . "login_user_id_valid_from = NULL, "
|
||||
// . "login_user_id_valid_until = NULL "
|
||||
// . "WHERE LOWER(username) = "
|
||||
// . self::$db->dbEscapeLiteral($mock_settings['test_username'])
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
// - loginGetAclList (null, invalid,)
|
||||
@@ -1126,7 +1830,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
* @param string $input
|
||||
* @return void
|
||||
*/
|
||||
public function testACLLoginGetPasswordLenght(string $input): void
|
||||
public function testACLLoginGetPasswordLength(string $input): void
|
||||
{
|
||||
$_SESSION = [];
|
||||
// init session (as MOCK)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# PARAMETER 2: db user WHO MUST BE ABLE TO CREATE A DATABASE
|
||||
# PARAMETER 3: db name
|
||||
# PARAMETER 4: db host
|
||||
# PARAMETER 5: print out for testing
|
||||
|
||||
load_sql="${1}";
|
||||
# abort with 1 if we cannot find the file
|
||||
@@ -34,8 +35,13 @@ if [ $? -ne 0 ]; then
|
||||
echo 4;
|
||||
exit 4;
|
||||
fi;
|
||||
# load data (redirect ALL error to null), on error exit with 5
|
||||
psql -U ${db_user} -h ${db_host} -f ${load_sql} ${db_name} 2>&1 1>/dev/null 2>/dev/null;
|
||||
# if error 5 thrown, test with enabled below
|
||||
if [ ! -z "${5}" ]; then
|
||||
psql -U ${db_user} -h ${db_host} -f ${load_sql} ${db_name};
|
||||
else
|
||||
# load data (redirect ALL error to null), on error exit with 5
|
||||
psql -U ${db_user} -h ${db_host} -f ${load_sql} ${db_name} 2>&1 1>/dev/null 2>/dev/null;
|
||||
fi;
|
||||
if [ $? -ne 0 ]; then
|
||||
echo 5;
|
||||
exit 5;
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
-- create random string with length X
|
||||
|
||||
CREATE FUNCTION random_string(randomLength int)
|
||||
RETURNS text AS $$
|
||||
RETURNS text AS
|
||||
$$
|
||||
SELECT array_to_string(
|
||||
ARRAY(
|
||||
SELECT substring(
|
||||
@@ -14,53 +15,58 @@ SELECT array_to_string(
|
||||
),
|
||||
''
|
||||
)
|
||||
$$ LANGUAGE SQL
|
||||
$$
|
||||
LANGUAGE SQL
|
||||
RETURNS NULL ON NULL INPUT
|
||||
VOLATILE; -- LEAKPROOF;-- END: function/random_string.sql
|
||||
VOLATILE; -- LEAKPROOF;
|
||||
-- END: function/random_string.sql
|
||||
-- START: function/set_edit_generic.sql
|
||||
-- adds the created or updated date tags
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_edit_generic() RETURNS TRIGGER AS '
|
||||
DECLARE
|
||||
random_length INT = 12; -- that should be long enough
|
||||
BEGIN
|
||||
IF TG_OP = ''INSERT'' THEN
|
||||
NEW.date_created := ''now'';
|
||||
NEW.cuid := random_string(random_length);
|
||||
ELSIF TG_OP = ''UPDATE'' THEN
|
||||
NEW.date_updated := ''now'';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
' LANGUAGE 'plpgsql';
|
||||
CREATE OR REPLACE FUNCTION set_edit_generic()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
random_length INT = 12; -- that should be long enough
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
NEW.date_created := 'now';
|
||||
NEW.cuid := random_string(random_length);
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
NEW.date_updated := 'now';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/set_edit_generic.sql
|
||||
-- START: function/edit_access_set_uid.sql
|
||||
-- add uid add for edit_access table
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_edit_access_uid() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_access t WHERE edit_access_id = NEW.edit_access_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_access t WHERE edit_access_id = NEW.edit_access_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/edit_access_set_uid.sql
|
||||
@@ -69,28 +75,28 @@ $$
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_edit_group_uid() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
DECLARE
|
||||
myrec RECORD;
|
||||
v_uid VARCHAR;
|
||||
BEGIN
|
||||
-- skip if NEW.name is not set
|
||||
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
|
||||
-- use NEW.name as base, remove all spaces
|
||||
-- name data is already unique, so we do not need to worry about this here
|
||||
v_uid := REPLACE(NEW.name, ' ', '');
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- always set
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_group t WHERE edit_group_id = NEW.edit_group_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- check if not set, then set
|
||||
SELECT INTO myrec t.* FROM edit_group t WHERE edit_group_id = NEW.edit_group_id;
|
||||
IF FOUND THEN
|
||||
NEW.uid := v_uid;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/edit_group_set_uid.sql
|
||||
@@ -246,6 +252,32 @@ END
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/edit_log_partition_insert.sql
|
||||
-- START: function/edit_user_set_login_user_id_set_date.sql
|
||||
-- set edit user login_user_id_set_date if login_user_id is set
|
||||
-- NOW() if not empty
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_login_user_id_set_date()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
-- if new is not null/empty
|
||||
-- and old one is null or old one different new one
|
||||
-- set NOW()
|
||||
-- if new one is NULL
|
||||
-- set NULL
|
||||
IF
|
||||
NEW.login_user_id IS NOT NULL AND NEW.login_user_id <> '' AND
|
||||
(OLD.login_user_id IS NULL OR NEW.login_user_id <> OLD.login_user_id)
|
||||
THEN
|
||||
NEW.login_user_id_set_date = NOW();
|
||||
ELSIF NEW.login_user_id IS NULL OR NEW.login_user_id = '' THEN
|
||||
NEW.login_user_id_set_date = NULL;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- END: function/edit_user_set_login_user_id_set_date.sql
|
||||
-- START: table/edit_temp_files.sql
|
||||
-- AUTHOR: Clemens Schwaighofer
|
||||
-- DATE: 2005/07/08
|
||||
@@ -526,34 +558,80 @@ CREATE TABLE edit_user (
|
||||
FOREIGN KEY (edit_scheme_id) REFERENCES edit_scheme (edit_scheme_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
edit_access_right_id INT NOT NULL,
|
||||
FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
enabled SMALLINT NOT NULL DEFAULT 0,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0,
|
||||
-- username/password
|
||||
username VARCHAR UNIQUE,
|
||||
password VARCHAR,
|
||||
-- name block
|
||||
first_name VARCHAR,
|
||||
last_name VARCHAR,
|
||||
first_name_furigana VARCHAR,
|
||||
last_name_furigana VARCHAR,
|
||||
-- email
|
||||
email VARCHAR,
|
||||
-- eanbled/deleted flag
|
||||
enabled SMALLINT NOT NULL DEFAULT 0,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0,
|
||||
-- general flags
|
||||
strict SMALLINT DEFAULT 0,
|
||||
locked SMALLINT DEFAULT 0,
|
||||
protected SMALLINT NOT NULL DEFAULT 0,
|
||||
-- legacy, debug flags
|
||||
debug SMALLINT NOT NULL DEFAULT 0,
|
||||
db_debug SMALLINT NOT NULL DEFAULT 0,
|
||||
email VARCHAR,
|
||||
protected SMALLINT NOT NULL DEFAULT 0,
|
||||
-- is admin user
|
||||
admin SMALLINT NOT NULL DEFAULT 0,
|
||||
-- last login log
|
||||
last_login TIMESTAMP WITHOUT TIME ZONE,
|
||||
-- login error
|
||||
login_error_count INT DEFAULT 0,
|
||||
login_error_date_last TIMESTAMP WITHOUT TIME ZONE,
|
||||
login_error_date_first TIMESTAMP WITHOUT TIME ZONE,
|
||||
strict SMALLINT DEFAULT 0,
|
||||
locked SMALLINT DEFAULT 0,
|
||||
-- time locked
|
||||
lock_until TIMESTAMP WITHOUT TIME ZONE,
|
||||
lock_after TIMESTAMP WITHOUT TIME ZONE,
|
||||
-- password change
|
||||
password_change_date TIMESTAMP WITHOUT TIME ZONE, -- only when password is first set or changed
|
||||
password_change_interval INTERVAL, -- null if no change is needed, or d/m/y time interval
|
||||
password_reset_time TIMESTAMP WITHOUT TIME ZONE, -- when the password reset was requested
|
||||
password_reset_uid VARCHAR, -- the uid to access the password reset page
|
||||
-- _GET login id for direct login
|
||||
login_user_id VARCHAR, -- the login uid, at least 32 chars
|
||||
login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE, -- when above uid was set
|
||||
login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE, -- if set, from when the above uid is valid
|
||||
login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE, -- if set, until when the above uid is valid
|
||||
login_user_id_revalidate_after INTERVAL DEFAULT '0 days', -- user must login to revalidated login id after set days, 0 for forever
|
||||
login_user_id_locked SMALLINT DEFAULT 0, -- lock for login user id, but still allow normal login
|
||||
-- additional ACL json block
|
||||
additional_acl JSONB -- additional ACL as JSON string (can be set by other pages)
|
||||
) INHERITS (edit_generic) WITHOUT OIDS;
|
||||
|
||||
COMMENT ON COLUMN edit_user.username IS 'Login username, must set';
|
||||
COMMENT ON COLUMN edit_user.password IS 'Login password, must set';
|
||||
COMMENT ON COLUMN edit_user.enabled IS 'Login is enabled (master switch)';
|
||||
COMMENT ON COLUMN edit_user.deleted IS 'Login is deleted (master switch), overrides all other';
|
||||
COMMENT ON COLUMN edit_user.strict IS 'If too many failed logins user will be locked, default off';
|
||||
COMMENT ON COLUMN edit_user.locked IS 'Locked from too many wrong password logins';
|
||||
COMMENT ON COLUMN edit_user.protected IS 'User can only be chnaged by admin user';
|
||||
COMMENT ON COLUMN edit_user.debug IS 'Turn debug flag on (legacy)';
|
||||
COMMENT ON COLUMN edit_user.db_debug IS 'Turn DB debug flag on (legacy)';
|
||||
COMMENT ON COLUMN edit_user.admin IS 'If set, this user is SUPER admin';
|
||||
COMMENT ON COLUMN edit_user.last_login IS 'Last succesfull login tiemstamp';
|
||||
COMMENT ON COLUMN edit_user.login_error_count IS 'Number of failed logins, reset on successful login';
|
||||
COMMENT ON COLUMN edit_user.login_error_date_last IS 'Last login error date';
|
||||
COMMENT ON COLUMN edit_user.login_error_date_first IS 'First login error date, reset on successfull login';
|
||||
COMMENT ON COLUMN edit_user.lock_until IS 'Account is locked until this date, <';
|
||||
COMMENT ON COLUMN edit_user.lock_after IS 'Account is locked after this date, >';
|
||||
COMMENT ON COLUMN edit_user.password_change_date IS 'Password was changed on';
|
||||
COMMENT ON COLUMN edit_user.password_change_interval IS 'After how many days the password has to be changed';
|
||||
COMMENT ON COLUMN edit_user.password_reset_time IS 'When the password reset was requested. For reset page uid valid check';
|
||||
COMMENT ON COLUMN edit_user.password_reset_uid IS 'Password reset page uid';
|
||||
COMMENT ON COLUMN edit_user.password_reset_uid IS 'Password reset page uid, one time, invalid after reset successful or time out';
|
||||
COMMENT ON COLUMN edit_user.login_user_id IS 'Min 32 character UID to be used to login without password. Via GET/POST parameter';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_set_date IS 'login id was set at what date';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_valid_from IS 'login id is valid from this date, >=';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_valid_until IS 'login id is valid until this date, <=';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_revalidate_after IS 'If set to a number greater 0 then user must login after given amount of days to revalidate, set to 0 for valid forver';
|
||||
COMMENT ON COLUMN edit_user.login_user_id_locked IS 'A separte lock flag for login id, user can still login normal';
|
||||
COMMENT ON COLUMN edit_user.additional_acl IS 'Additional Access Control List stored in JSON format';
|
||||
-- END: table/edit_user.sql
|
||||
-- START: table/edit_log.sql
|
||||
-- AUTHOR: Clemens Schwaighofer
|
||||
@@ -774,6 +852,11 @@ FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
|
||||
CREATE TRIGGER trg_edit_user
|
||||
BEFORE INSERT OR UPDATE ON edit_user
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
|
||||
|
||||
-- DROP TRIGGER IF EXISTS trg_edit_user_set_login_user_id_set_date ON edit_user;
|
||||
CREATE TRIGGER trg_edit_user_set_login_user_id_set_date
|
||||
BEFORE INSERT OR UPDATE ON edit_user
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_login_user_id_set_date();
|
||||
-- END: trigger/trg_edit_user.sql
|
||||
-- START: trigger/trg_edit_visible_group.sql
|
||||
-- DROP TRIGGER IF EXISTS trg_edit_visible_group ON edit_visible_group;
|
||||
|
||||
Reference in New Issue
Block a user