feat #466: add deny permission effect
This commit is contained in:
@@ -65,7 +65,8 @@ CREATE TABLE cb_permission (
|
||||
perm_id NUMBER PRIMARY KEY,
|
||||
role_id NUMBER NOT NULL REFERENCES cb_app_role(role_id),
|
||||
target_name VARCHAR2(128) NOT NULL,
|
||||
action_name VARCHAR2(30) NOT NULL
|
||||
action_name VARCHAR2(30) NOT NULL,
|
||||
permission_effect VARCHAR2(10) DEFAULT 'ALLOW' NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE cb_permission_rule (
|
||||
@@ -106,9 +107,9 @@ INSERT INTO cb_user_role VALUES (101, 10);
|
||||
INSERT INTO cb_user_role VALUES (102, 20);
|
||||
INSERT INTO cb_user_role VALUES (103, 30);
|
||||
|
||||
INSERT INTO cb_permission VALUES (100, 10, 'CB_V_SEARCH_DOCUMENTS', 'SELECT');
|
||||
INSERT INTO cb_permission VALUES (200, 20, 'CB_V_SEARCH_DOCUMENTS', 'SELECT');
|
||||
INSERT INTO cb_permission VALUES (300, 30, 'CB_V_SEARCH_DOCUMENTS', 'SELECT');
|
||||
INSERT INTO cb_permission VALUES (100, 10, 'CB_V_SEARCH_DOCUMENTS', 'SELECT', 'ALLOW');
|
||||
INSERT INTO cb_permission VALUES (200, 20, 'CB_V_SEARCH_DOCUMENTS', 'SELECT', 'ALLOW');
|
||||
INSERT INTO cb_permission VALUES (300, 30, 'CB_V_SEARCH_DOCUMENTS', 'SELECT', 'ALLOW');
|
||||
|
||||
INSERT INTO cb_permission_rule VALUES (1000, 100, 'MY_DEPT', NULL);
|
||||
INSERT INTO cb_permission_rule VALUES (2000, 200, 'SELF', NULL);
|
||||
@@ -256,7 +257,8 @@ AUTHID DEFINER
|
||||
AS
|
||||
v_user_id NUMBER;
|
||||
v_target VARCHAR2(128);
|
||||
v_predicate VARCHAR2(32767);
|
||||
v_allow_predicate VARCHAR2(32767);
|
||||
v_deny_predicate VARCHAR2(32767);
|
||||
|
||||
FUNCTION quote_literal(p_value IN VARCHAR2) RETURN VARCHAR2 IS
|
||||
BEGIN
|
||||
@@ -294,16 +296,22 @@ AS
|
||||
RETURN NULL;
|
||||
END;
|
||||
|
||||
PROCEDURE append_or(p_clause IN VARCHAR2) IS
|
||||
PROCEDURE append_or(p_effect IN VARCHAR2, p_clause IN VARCHAR2) IS
|
||||
BEGIN
|
||||
IF p_clause IS NULL THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
IF v_predicate IS NULL THEN
|
||||
v_predicate := '(' || p_clause || ')';
|
||||
IF p_effect = 'DENY' THEN
|
||||
IF v_deny_predicate IS NULL THEN
|
||||
v_deny_predicate := '(' || p_clause || ')';
|
||||
ELSE
|
||||
v_deny_predicate := v_deny_predicate || ' OR (' || p_clause || ')';
|
||||
END IF;
|
||||
ELSIF v_allow_predicate IS NULL THEN
|
||||
v_allow_predicate := '(' || p_clause || ')';
|
||||
ELSE
|
||||
v_predicate := v_predicate || ' OR (' || p_clause || ')';
|
||||
v_allow_predicate := v_allow_predicate || ' OR (' || p_clause || ')';
|
||||
END IF;
|
||||
END;
|
||||
BEGIN
|
||||
@@ -323,6 +331,7 @@ BEGIN
|
||||
FOR r IN (
|
||||
SELECT UPPER(TRIM(r.rule_type)) AS rule_type,
|
||||
UPPER(TRIM(r.rule_column)) AS rule_column,
|
||||
NVL(UPPER(TRIM(p.permission_effect)), 'ALLOW') AS permission_effect,
|
||||
r.rule_value
|
||||
FROM cb_user_role ur
|
||||
JOIN cb_permission p
|
||||
@@ -338,46 +347,56 @@ BEGIN
|
||||
v_column VARCHAR2(128);
|
||||
BEGIN
|
||||
IF r.rule_type = 'ALL' THEN
|
||||
RETURN '1 = 1';
|
||||
IF r.permission_effect = 'DENY' THEN
|
||||
RETURN '1 = 0';
|
||||
END IF;
|
||||
v_allow_predicate := '(1 = 1)';
|
||||
ELSIF r.rule_type = 'MY_DEPT' THEN
|
||||
v_column := safe_column(p_schema, p_object, NVL(r.rule_column, 'DEPT_CODE'));
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or(v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''DEPT_CODE'')');
|
||||
append_or(r.permission_effect, v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''DEPT_CODE'')');
|
||||
END IF;
|
||||
ELSIF r.rule_type = 'SELF' THEN
|
||||
v_column := safe_column(p_schema, p_object, NVL(r.rule_column, 'OWNER_EMP_NO'));
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or(v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''EMP_NO'')');
|
||||
append_or(r.permission_effect, v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''EMP_NO'')');
|
||||
END IF;
|
||||
ELSIF r.rule_type = 'DEPT' THEN
|
||||
v_column := safe_column(p_schema, p_object, NVL(r.rule_column, 'DEPT_CODE'));
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or(v_column || ' = ' || quote_literal(r.rule_value));
|
||||
append_or(r.permission_effect, v_column || ' = ' || quote_literal(r.rule_value));
|
||||
END IF;
|
||||
ELSIF r.rule_type = 'EMP_NO' THEN
|
||||
v_column := safe_column(p_schema, p_object, NVL(r.rule_column, 'OWNER_EMP_NO'));
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or(v_column || ' = ' || quote_literal(r.rule_value));
|
||||
append_or(r.permission_effect, v_column || ' = ' || quote_literal(r.rule_value));
|
||||
END IF;
|
||||
ELSIF r.rule_type = '=' THEN
|
||||
v_column := safe_column(p_schema, p_object, r.rule_column);
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or('TO_CHAR(' || v_column || ') = ' || quote_literal(r.rule_value));
|
||||
append_or(r.permission_effect, 'TO_CHAR(' || v_column || ') = ' || quote_literal(r.rule_value));
|
||||
END IF;
|
||||
ELSIF r.rule_type IN ('!=', '<>') THEN
|
||||
v_column := safe_column(p_schema, p_object, r.rule_column);
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or('TO_CHAR(' || v_column || ') <> ' || quote_literal(r.rule_value));
|
||||
append_or(r.permission_effect, 'TO_CHAR(' || v_column || ') <> ' || quote_literal(r.rule_value));
|
||||
END IF;
|
||||
END IF;
|
||||
END;
|
||||
END LOOP;
|
||||
|
||||
IF v_predicate IS NULL THEN
|
||||
IF v_allow_predicate IS NULL THEN
|
||||
RETURN '1 = 0';
|
||||
END IF;
|
||||
|
||||
RETURN '(' || v_predicate || ')';
|
||||
IF v_deny_predicate IS NULL THEN
|
||||
IF v_allow_predicate = '(1 = 1)' THEN
|
||||
RETURN '1 = 1';
|
||||
END IF;
|
||||
RETURN '(' || v_allow_predicate || ')';
|
||||
END IF;
|
||||
|
||||
RETURN '((' || v_allow_predicate || ') AND NOT (' || v_deny_predicate || '))';
|
||||
END;
|
||||
/
|
||||
|
||||
|
||||
@@ -52,6 +52,16 @@ EXCEPTION
|
||||
END;
|
||||
/
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'ALTER TABLE cb_permission ADD (permission_effect VARCHAR2(10) DEFAULT ''ALLOW'' NOT NULL)';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -1430 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE TABLE cb_protected_object (
|
||||
object_id NUMBER PRIMARY KEY,
|
||||
owner VARCHAR2(128) NOT NULL,
|
||||
|
||||
@@ -22,7 +22,8 @@ AS
|
||||
-- no matched stored row rule means no rows are visible.
|
||||
v_user_id NUMBER;
|
||||
v_target VARCHAR2(128);
|
||||
v_predicate VARCHAR2(32767);
|
||||
v_allow_predicate VARCHAR2(32767);
|
||||
v_deny_predicate VARCHAR2(32767);
|
||||
|
||||
FUNCTION quote_literal(p_value IN VARCHAR2) RETURN VARCHAR2 IS
|
||||
BEGIN
|
||||
@@ -60,16 +61,22 @@ AS
|
||||
RETURN NULL;
|
||||
END;
|
||||
|
||||
PROCEDURE append_or(p_clause IN VARCHAR2) IS
|
||||
PROCEDURE append_or(p_effect IN VARCHAR2, p_clause IN VARCHAR2) IS
|
||||
BEGIN
|
||||
IF p_clause IS NULL THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
IF v_predicate IS NULL THEN
|
||||
v_predicate := '(' || p_clause || ')';
|
||||
IF p_effect = 'DENY' THEN
|
||||
IF v_deny_predicate IS NULL THEN
|
||||
v_deny_predicate := '(' || p_clause || ')';
|
||||
ELSE
|
||||
v_deny_predicate := v_deny_predicate || ' OR (' || p_clause || ')';
|
||||
END IF;
|
||||
ELSIF v_allow_predicate IS NULL THEN
|
||||
v_allow_predicate := '(' || p_clause || ')';
|
||||
ELSE
|
||||
v_predicate := v_predicate || ' OR (' || p_clause || ')';
|
||||
v_allow_predicate := v_allow_predicate || ' OR (' || p_clause || ')';
|
||||
END IF;
|
||||
END;
|
||||
BEGIN
|
||||
@@ -89,6 +96,7 @@ BEGIN
|
||||
FOR r IN (
|
||||
SELECT UPPER(TRIM(r.rule_type)) AS rule_type,
|
||||
UPPER(TRIM(r.rule_column)) AS rule_column,
|
||||
NVL(UPPER(TRIM(p.permission_effect)), 'ALLOW') AS permission_effect,
|
||||
r.rule_value
|
||||
FROM cb_user_role ur
|
||||
JOIN cb_permission p
|
||||
@@ -104,48 +112,58 @@ BEGIN
|
||||
v_column VARCHAR2(128);
|
||||
BEGIN
|
||||
IF r.rule_type = 'ALL' THEN
|
||||
RETURN '1 = 1';
|
||||
IF r.permission_effect = 'DENY' THEN
|
||||
RETURN '1 = 0';
|
||||
END IF;
|
||||
v_allow_predicate := '(1 = 1)';
|
||||
ELSIF r.rule_type = 'MY_DEPT' THEN
|
||||
-- NULL rule_column keeps backward compatibility with the demo seed.
|
||||
v_column := safe_column(p_schema, p_object, NVL(r.rule_column, 'DEPT_CODE'));
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or(v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''DEPT_CODE'')');
|
||||
append_or(r.permission_effect, v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''DEPT_CODE'')');
|
||||
END IF;
|
||||
ELSIF r.rule_type = 'SELF' THEN
|
||||
-- NULL rule_column keeps backward compatibility with the demo seed.
|
||||
v_column := safe_column(p_schema, p_object, NVL(r.rule_column, 'OWNER_EMP_NO'));
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or(v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''EMP_NO'')');
|
||||
append_or(r.permission_effect, v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''EMP_NO'')');
|
||||
END IF;
|
||||
ELSIF r.rule_type = 'DEPT' THEN
|
||||
v_column := safe_column(p_schema, p_object, NVL(r.rule_column, 'DEPT_CODE'));
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or(v_column || ' = ' || quote_literal(r.rule_value));
|
||||
append_or(r.permission_effect, v_column || ' = ' || quote_literal(r.rule_value));
|
||||
END IF;
|
||||
ELSIF r.rule_type = 'EMP_NO' THEN
|
||||
v_column := safe_column(p_schema, p_object, NVL(r.rule_column, 'OWNER_EMP_NO'));
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or(v_column || ' = ' || quote_literal(r.rule_value));
|
||||
append_or(r.permission_effect, v_column || ' = ' || quote_literal(r.rule_value));
|
||||
END IF;
|
||||
ELSIF r.rule_type = '=' THEN
|
||||
v_column := safe_column(p_schema, p_object, r.rule_column);
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or('TO_CHAR(' || v_column || ') = ' || quote_literal(r.rule_value));
|
||||
append_or(r.permission_effect, 'TO_CHAR(' || v_column || ') = ' || quote_literal(r.rule_value));
|
||||
END IF;
|
||||
ELSIF r.rule_type IN ('!=', '<>') THEN
|
||||
v_column := safe_column(p_schema, p_object, r.rule_column);
|
||||
IF v_column IS NOT NULL THEN
|
||||
append_or('TO_CHAR(' || v_column || ') <> ' || quote_literal(r.rule_value));
|
||||
append_or(r.permission_effect, 'TO_CHAR(' || v_column || ') <> ' || quote_literal(r.rule_value));
|
||||
END IF;
|
||||
END IF;
|
||||
END;
|
||||
END LOOP;
|
||||
|
||||
IF v_predicate IS NULL THEN
|
||||
IF v_allow_predicate IS NULL THEN
|
||||
RETURN '1 = 0';
|
||||
END IF;
|
||||
|
||||
RETURN '(' || v_predicate || ')';
|
||||
IF v_deny_predicate IS NULL THEN
|
||||
IF v_allow_predicate = '(1 = 1)' THEN
|
||||
RETURN '1 = 1';
|
||||
END IF;
|
||||
RETURN '(' || v_allow_predicate || ')';
|
||||
END IF;
|
||||
|
||||
RETURN '((' || v_allow_predicate || ') AND NOT (' || v_deny_predicate || '))';
|
||||
END;
|
||||
/
|
||||
|
||||
|
||||
@@ -61,6 +61,12 @@ BEGIN
|
||||
INSERT INTO cb_app_user(user_id, user_name, employee_no, dept_code, can_read_contents, active)
|
||||
VALUES (456110, 'rule_test_target_mismatch', 'E456110', 'QA', 'N', 'Y');
|
||||
|
||||
INSERT INTO cb_app_user(user_id, user_name, employee_no, dept_code, can_read_contents, active)
|
||||
VALUES (456111, 'rule_test_allow_deny', 'E456111', 'HR', 'N', 'Y');
|
||||
|
||||
INSERT INTO cb_app_user(user_id, user_name, employee_no, dept_code, can_read_contents, active)
|
||||
VALUES (456112, 'rule_test_deny_only', 'E456112', 'HR', 'N', 'Y');
|
||||
|
||||
INSERT INTO cb_app_role(role_id, role_name) VALUES (456101, 'RULE_TEST_MY_DEPT');
|
||||
INSERT INTO cb_app_role(role_id, role_name) VALUES (456102, 'RULE_TEST_SELF');
|
||||
INSERT INTO cb_app_role(role_id, role_name) VALUES (456103, 'RULE_TEST_ALL');
|
||||
@@ -71,6 +77,8 @@ BEGIN
|
||||
INSERT INTO cb_app_role(role_id, role_name) VALUES (456108, 'RULE_TEST_OR_INJECTION');
|
||||
INSERT INTO cb_app_role(role_id, role_name) VALUES (456109, 'RULE_TEST_COLUMN_INJECTION');
|
||||
INSERT INTO cb_app_role(role_id, role_name) VALUES (456110, 'RULE_TEST_TARGET_MISMATCH');
|
||||
INSERT INTO cb_app_role(role_id, role_name) VALUES (456111, 'RULE_TEST_ALLOW_DENY');
|
||||
INSERT INTO cb_app_role(role_id, role_name) VALUES (456112, 'RULE_TEST_DENY_ONLY');
|
||||
|
||||
INSERT INTO cb_user_role(user_id, role_id) VALUES (456101, 456101);
|
||||
INSERT INTO cb_user_role(user_id, role_id) VALUES (456102, 456102);
|
||||
@@ -82,6 +90,8 @@ BEGIN
|
||||
INSERT INTO cb_user_role(user_id, role_id) VALUES (456108, 456108);
|
||||
INSERT INTO cb_user_role(user_id, role_id) VALUES (456109, 456109);
|
||||
INSERT INTO cb_user_role(user_id, role_id) VALUES (456110, 456110);
|
||||
INSERT INTO cb_user_role(user_id, role_id) VALUES (456111, 456111);
|
||||
INSERT INTO cb_user_role(user_id, role_id) VALUES (456112, 456112);
|
||||
|
||||
INSERT INTO cb_permission(perm_id, role_id, target_name, action_name)
|
||||
VALUES (456101, 456101, 'CB_V_SEARCH_DOCUMENTS', 'SELECT');
|
||||
@@ -113,6 +123,15 @@ BEGIN
|
||||
INSERT INTO cb_permission(perm_id, role_id, target_name, action_name)
|
||||
VALUES (456110, 456110, 'BOARD_POSTS', 'SELECT');
|
||||
|
||||
INSERT INTO cb_permission(perm_id, role_id, target_name, action_name, permission_effect)
|
||||
VALUES (456111, 456111, 'CB_V_SEARCH_DOCUMENTS', 'SELECT', 'ALLOW');
|
||||
|
||||
INSERT INTO cb_permission(perm_id, role_id, target_name, action_name, permission_effect)
|
||||
VALUES (456112, 456111, 'CB_V_SEARCH_DOCUMENTS', 'SELECT', 'DENY');
|
||||
|
||||
INSERT INTO cb_permission(perm_id, role_id, target_name, action_name, permission_effect)
|
||||
VALUES (456113, 456112, 'CB_V_SEARCH_DOCUMENTS', 'SELECT', 'DENY');
|
||||
|
||||
INSERT INTO cb_permission_rule(rule_id, perm_id, rule_column, rule_type, rule_value)
|
||||
VALUES (456101, 456101, NULL, 'MY_DEPT', NULL);
|
||||
|
||||
@@ -143,6 +162,15 @@ BEGIN
|
||||
INSERT INTO cb_permission_rule(rule_id, perm_id, rule_column, rule_type, rule_value)
|
||||
VALUES (456110, 456110, NULL, 'ALL', NULL);
|
||||
|
||||
INSERT INTO cb_permission_rule(rule_id, perm_id, rule_column, rule_type, rule_value)
|
||||
VALUES (456111, 456111, NULL, 'ALL', NULL);
|
||||
|
||||
INSERT INTO cb_permission_rule(rule_id, perm_id, rule_column, rule_type, rule_value)
|
||||
VALUES (456112, 456112, 'DEPT_CODE', '=', 'HR');
|
||||
|
||||
INSERT INTO cb_permission_rule(rule_id, perm_id, rule_column, rule_type, rule_value)
|
||||
VALUES (456113, 456113, 'DEPT_CODE', '=', 'HR');
|
||||
|
||||
COMMIT;
|
||||
END;
|
||||
/
|
||||
@@ -229,6 +257,9 @@ BEGIN
|
||||
assert_equals('COLUMN_INJECTION_DENIES', 456109, '1 = 0');
|
||||
assert_equals_for_object('TARGET_MISMATCH_DENIES', 456110, 'CB_V_SEARCH_DOCUMENTS', '1 = 0');
|
||||
assert_equals_for_object('TARGET_MATCH_ALL_ALLOWS', 456110, 'BOARD_POSTS', '1 = 1');
|
||||
assert_contains('ALLOW_ALL_MINUS_DENY_DEPT', 456111, 'AND NOT');
|
||||
assert_contains('ALLOW_ALL_MINUS_DENY_DEPT_DETAIL', 456111, 'TO_CHAR(DEPT_CODE) = ''HR''');
|
||||
assert_equals('DENY_ONLY_DENIES', 456112, '1 = 0');
|
||||
cb_agent_ctx_pkg.clear_user;
|
||||
END;
|
||||
/
|
||||
|
||||
Reference in New Issue
Block a user