问题
Hello, I have asked this question yesterday but thanks to your help, I did a lot of modifications so now I'm putting the new version of my code because it's getting better but still not working.
Let's assume i have the following table which is called payroll
created by a user called PCM
EMP_ID DEPT TOTAL TAXES
-------------------- -------------------- ---------- ----------
E1 accounting 2400 100
E2 sales 2500 75
E3 research 3000 110
E4 operations 4200 120
E5 sales 4800 130
E6 sales 2500 75
E7 accounting 5200 140
E8 accounting 2700 105
Now what i want to achieve is the following: Anyone with the dept = accounting"
can select all other rows with dept != accounting
but anyone with dept != accounting
can only view his/her record.
Now I'm connected as another user not the owner of the payroll table so I'm connected as a user called ANNE
:
CREATE OR REPLACE CONTEXT payroll_ctx USING payroll_ctx_pkg;
CREATE OR REPLACE PACKAGE payroll_ctx_pkg IS
PROCEDURE set_dept;
END;
/
CREATE OR REPLACE PACKAGE BODY payroll_ctx_pkg IS
PROCEDURE set_dept
AS
v_dept varchar2(400);
BEGIN
SELECT dept INTO v_dept FROM PCM.PAYROLL
WHERE EMP_ID = SYS_CONTEXT('USERENV', 'SESSION_USER');
DBMS_SESSION.SET_CONTEXT('payroll_ctx', 'dept', v_dept);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_SESSION.SET_CONTEXT('payroll_ctx', 'dept', 'NO');
END set_dept;
END;
/
Considering that the users who will try to access the table have the names of the emp_id column,now:
CREATE TRIGGER set_dept_trig AFTER LOGON ON DATABASE
BEGIN
ANNE.payroll_ctx_pkg.set_dept;
END;
/
Now the problem(i know it's wrong) but can't find the solution yet:
CREATE OR REPLACE PACKAGE security_package AS
FUNCTION sec_fun (D1 VARCHAR2, D2 VARCHAR2)
RETURN VARCHAR2;
END;
/
CREATE OR REPLACE PACKAGE BODY security_package AS
FUNCTION sec_fun (D1 VARCHAR2, D2 VARCHAR2)
RETURN VARCHAR2
IS
vv_dept varchar2(400);
V_ID varchar2(400);
begin
V_ID := SYS_CONTEXT('USERENV', 'SESSION_USER');
vv_dept := 'SYS_CONTEXT(''payroll_ctx'', ''dept'')';
if (vv_dept != 'accounting') then
RETURN 'EMP_ID = ' || CHR(39)||V_ID||CHR(39);
ELSE
RETURN 'DEPT != ' || CHR(39)||vv_dept||CHR(39);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN '1 = 0';
end sec_fun;
end security_package;
/
And Finally:
BEGIN
DBMS_RLS.ADD_POLICY (
object_schema => 'PCM',
object_name => 'PAYROLL',
policy_name => 'payroll_policy',
function_schema => 'ANNE',
policy_function => 'security_package.sec_fun',
statement_types => 'select');
END;
/
Now when a user E1
tries to select from payroll the output is:
EMP_ID DEPT TOTAL TAXES
-------------------- -------------------- ---------- ----------
E1 accounting 2400 100
what I'm doing wrong?? It's supposed to return all rows where dept != accounting
回答1:
Thanks to your helping i finally managed to solve the problem, It was in the variable vv_dept when i made the following modifications it worked out:
CREATE OR REPLACE PACKAGE security_package AS
FUNCTION sec_fun (D1 VARCHAR2, D2 VARCHAR2)
RETURN VARCHAR2;
END;
/
CREATE OR REPLACE PACKAGE BODY security_package AS
FUNCTION sec_fun (D1 VARCHAR2, D2 VARCHAR2)
RETURN VARCHAR2
IS
V_ID varchar2(400);
begin
V_ID := SYS_CONTEXT('USERENV', 'SESSION_USER');
if (SYS_CONTEXT('payroll_ctx','dept') = 'accounting') then
RETURN 'DEPT != ' || CHR(39)||SYS_CONTEXT('payroll_ctx','dept')||CHR(39);
ELSE
RETURN 'EMP_ID = ' || CHR(39)||V_ID||CHR(39);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN '1 = 0';
end sec_fun;
end security_package;
/
来源:https://stackoverflow.com/questions/53816394/vpd-policy-function-modified