How to create policy for user in system schema in Oracle? - oracle

I logged in as system and coded this:
CREATE TABLE EMPHOLIDAY(
EmpNo NUMBER(5),
m_Name VARCHAR2(60),
Holiday DATE
);
-- then i created 3 users:
ALTER SESSION SET "_ORACLE_SCRIPT" = TRUE;
CREATE USER Hann IDENTIFIED BY HANN;
CREATE USER Annu IDENTIFIED BY ANNU;
CREATE USER Theota IDENTIFIED BY THEOTA;
GRANT CREATE SESSION TO Hann;
GRANT CREATE SESSION TO Annu;
GRANT CREATE SESSION TO Theota;
Then i want to create policy like this:
1- 'Annu' can only SEE and Edit row of EMPHOLIDAY that has 'EmpNo' = 2.
2- 'Theota' can't see or edit EMPHOLIDAY.
3- 'Hann' can see all rows of EMPHOLDAY, but only can edit rows that have 'Holiday' >= CURRENT DATE.
I create the second policy like this:
CREATE OR REPLACE FUNCTION policy_2(
p_schema IN VARCHAR2,
P_object IN VARCHAR2
)
RETURN VARCHAR2
AS
BEGIN
RETURN 'USER != ''Theota''';
END;
/
BEGIN DBMS_RLS.add_policy(
object_schema => 'system',
object_name => 'EMPHOLIDAY',
policy_name => 'personalInfo',
policy_function => 'policy_2',
statement_types => 'SELECT, UPDATE, DELETE, INSERT',
update_check => TRUE
);
END;
And it worked. But for 2 other policies, i tried to change RETURN statement in POLICY_2 and statement_types some times but this seems not the right ways. Can someone help me solve these problems? Thanks alot.

Related

Automaticaly creating users in Oracle Apex based on table values

Is there a way to automatically create a user in my application based on values in a table?
So I have a table named EMP as employee in that table I have attributes name, surname, username and password. What do I need to do to automatically create a user account in my application when a new employee is inserted into the database?
I have no idea where to start, is that done in processes or is there a pre-built feature that covers this?
Is there a sample code that everyone just uses and adapts to their needs?
In such a case, maybe it would be better to use custom authentication scheme instead of default, built-in Apex authentication.
How to create new users? Just insert them into the table. It would be a good idea to create a package which contains procedures used to manipulate with users' data.
You shouldn't store passwords as text for security reasons.
For example:
procedure p_create_user (p_name in varchar2, p_surname in varchar2,
p_username in varchar2, p_password in varchar2)
is
l_hash raw (2000);
begin
l_hash :=
dbms_crypto.hash (
utl_i18n.string_to_raw (p_password, 'AL32UTF8'),
dbms_crypto.hash_sh1);
insert into emp (name, surname, username, password)
values
(p_name, p_surname, p_username, l_hash);
end;
In Apex, authentication scheme requires you to create your own function (and set its name into the "Authentication Function Name" property) which accepts username/password combination and returns Boolean: TRUE (if credentials are valid) or FALSE (if not). Note that parameters' names MUST be p_username and p_password.
Use code similar to that in previous procedure:
function f_auth (p_username in varchar2, p_password in varchar2)
return boolean
is
l_pwd emp.password%type;
begin
select password
into l_pwd
from emp
where username = p_username;
return l_pwd = dbms_crypto.hash (
utl_i18n.string_to_raw (p_password, 'AL32UTF8'),
dbms_crypto.hash_sh1);
end;
That's all you need for basic functionality. You can add another procedure to let users change their password etc.

How to apply Oracle VPD Policy to restrict update some specific columns?

I have some problems when trying to solve my homework about VPD Policy of Oracle. The question is "MYADMIN account has the right to select and update students' Enroll Information. But he is not allowed to see the Score of the student's Enroll Information as well as update the Score of the student's Enroll Information.
I have done the first task (they are not allowed to see the Score of the student's Enroll Information by using column masking), but when I trying to add the word "update" to statement_type to my code like this, the DBMS notifies errors. I have searched the Internet and realized that column masking can be only used for "Select" statment.
So if I want to apply the Oracle VPD Policy to restrict MYADMIN to update the Score of students' Enroll Information. How can I do that? Will I have to create a session_context view?
Here is my code. Thank you so much
CREATE OR REPLACE FUNCTION Question5
(p_schema IN VARCHAR2, p_object IN VARCHAR2)
RETURN VARCHAR2
AS
user_value VARCHAR2(60);
user varchar2(60);
BEGIN
user := SYS_CONTEXT('userenv','session_user');
user_value:= '(select (SYS_CONTEXT(''USERENV'',''SESSION_USER'')) from dual)';
IF(UPPER(user) = 'MYADMIN') THEN
RETURN 'USER != ''MYADMIN''';
ELSE
RETURN 'StudentID = ' || user_value;
END IF;
END;
/
BEGIN
DBMS_RLS.ADD_POLICY(
object_schema =>'SYSTEM',
object_name => 'EnrollInformation',
policy_name => 'Question5_MyAdmin',
statement_types => 'select, update',
function_schema => 'sec_mgr',
policy_function => 'Question5',
sec_relevant_cols => 'Score',
sec_relevant_cols_opt => dbms_rls.all_rows,
update_check => TRUE);
end;
/

What will be the procedure to run a job scheduler to send mails on apex oracle?

I have an apex application where i need to send a notification mail to all the employees on the 5th of every month. So just for the sake of testing i am trying to send a mail in every 30 seconds. I created a job scheduler on a procedure to do the same. Here is the PLSQL code for it.
create or replace procedure send_notification_employee as
cursor c_employee is select * from EMPLOYEE;
r_employee c_employee%ROWTYPE;
begin
open c_employee;
loop
fetch c_employee into r_employee;
exit when c_employee%NOTFOUND;
APEX_MAIL.SEND(
p_to => r_employee.EMPLOYEE_EMAIL,
p_from => 'abc#gmail.com',
p_subj => 'Reminder : Meeting',
p_body => '<Some random message>');
end loop;
close c_employee;
end;
/
begin
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'send_notification',
job_type => 'stored_procedure',
job_action => 'send_notification_employee',
start_date => NULL,
repeat_interval => 'FREQ=SECONDLY;INTERVAL=30',
end_date => NULL);
end;
/
begin
DBMS_SCHEDULER.enable(
name => 'send_notification');
end;
/
I guess the code is correct. The only thing i am not sure of is to how to run this scheduler on the apex oracle application. Should i just execute these statements on the SQL Commands or is there any other way to do it?
Also i tried to execute the same statements in the SQL Commands tab but i don't receive any mails as such. Is there any issue with my code? Thanks in advance.
You need to set the security group if sending the mail from the database rather than from APEX directly. You should also use push_queue at the end of the procedure to clear out the table of unsent mail.
create or replace procedure send_notification_employee as
cursor c_employee is select * from EMPLOYEE;
r_employee c_employee%ROWTYPE;
l_workspace number;
begin
-- Get a valid workspace ID
SELECT MAX(workspace_id) INTO l_workspace FROM apex_applications WHERE application_id = <valid application_id>;
-- Set Workspace
wwv_flow_api.set_security_group_id(l_workspace);
open c_employee;
loop
fetch c_employee into r_employee;
exit when c_employee%NOTFOUND;
APEX_MAIL.SEND(
p_to => r_employee.EMPLOYEE_EMAIL,
p_from => 'abc#gmail.com',
p_subj => 'Reminder : Meeting',
p_body => '<Some random message>');
end loop;
close c_employee;
-- Finally force send
APEX_MAIL.PUSH_QUEUE;
end;
Re. how to execute - it depends on what you want to do. If you just want to run it on the 5th of every month just setup a scheduled job in the db to do it, as you have above. If you want to run on an adhoc basis just create a job in an APEX after submit process that calls the procedure and executes through the database.
As an aside, if you plan to create many mail procedures you may wish to create a helper procedure to get the workspace id / send the mail, and just call it from your other mail procedures.
These queries could be handy (To check if you have the correct set up):
Check if util_smtp is installed:
select * from dba_objects where object_name like 'UTL_SMTP%'
Check privileges:
select grantee , table_name , privilege from dba_tab_privs where table_name = 'UTL_SMTP'
Check open network hosts, ports:
select acl , host , lower_port , upper_port from DBA_NETWORK_ACLS;
Check network privileges:
select acl , principal , privilege , is_grant from DBA_NETWORK_ACL_PRIVILEGES

Oracle PL/SQL dynamically create name for Procedure and Policy

I'm trying to see if the following would be possible.
it all hinges on creating Policies and Procedures for each row..
Is it possible to create a dynamically named Procedure and pass that name to a dynamically
named policy?
So as following create these in a loop ??
I have an email alert
CREATE OR REPLACE PROCEDURE caps_email_alert (sch varchar2, tab varchar2, pol varchar2)
AS
msg varchar2(20000) := 'CAPS.ME_PAYEE table violation. The time is: ';
BEGIN
msg := msg||to_char(SYSDATE, 'Day DD MON, YYYY HH24:MI:SS');
UTL_MAIL.SEND (
sender => 'me#somewhere.com',
recipients => 'me#somewhere.com',
subject => 'Table modification on caps.me_payee',
message => msg);
END caps_email_alert;
/
and a policy that will call it...
BEGIN
DBMS_FGA.ADD_POLICY (
object_schema => 'CAPS',
object_name => 'ME_PAYEE',
policy_name => 'CHK_CAPS_ME_PAYEE',
audit_column => 'CARRIER_NO',
audit_condition => 'CARRIER_NO = ''20'' ',
handler_schema => 'SYSADMIN_FGA',
handler_module => 'CAPS_EMAIL_ALERT',
enable => TRUE,
statement_types => 'SELECT, UPDATE',
audit_trail => DBMS_FGA.DB + DBMS_FGA.EXTENDED);
END;
/
I would need to write a subprogram that would execute as follows...
( to create a Procedure and Policy for each row )
BEGIN
FOR c IN (SELECT schema as sch, table as tab, cond as pred FROM slac_red_table) LOOP
--here need to create dynamically named procedure and pass it to a dynamically named policy
--so a function that creates a dynamically named procedure
emailerProcedureName emailerProcedureName%TYPE := emailerFunction(c.sch, c.tab)
createPolicyFunction(c.sch, c.tab, c.cond,emailerProcedureName)
END LOOP;
END;
Maybe I can accomplish the same some other way... have you encountered something similar ?

Oracle audit grant dba role

Running Oracle 11gR1 in an XP SP2 virtual machine. Full disclosure: This is for an assignment.
I'm attempting to audit whenever a user is granted the DBA role and fire off an email when the event occurs.
I believe the command AUDIT DBA; will audit all actions performed upon the DBA role. I have a fully working procedure which will take care of the email portion, but I'm not aware of a way for standard auditing to trigger the procedure in the same way a fine-grained auditing policy can.
I've tried using the policy
begin
dbms_fga.drop_policy
(object_schema => 'SYS',
object_name => 'DBA_ROLE_PRIVS',
policy_name => 'EXAMPLE');
dbms_fga.add_policy
(object_schema => 'SYS',
object_name => 'DBA_ROLE_PRIVS',
policy_name => 'EXAMPLE',
audit_condition => 'GRANTED_ROLE = DBA',
audit_column => 'GRANTED_ROLE',
handler_schema => 'SYS',
handler_module => 'FGA_NOTIFY');
end;
Where FGA_NOTIFY is the email procedure. But I get the notice "adding a policy to an object owned by SYS is not allowed." Searching through Oracle's documentation I have found no way around this.
My question is: can anyone suggest a method for auditing and Oracle database for when a user gains DBA role which can also trigger an email notification?
Thanks in advance for your help!
You could enable AUDIT_TRAIL and create a job that periodically querys the DBA_AUDIT_TRAIL view looking for the types of grants you want to check:
select os_username, username, userhost, terminal, timestamp, grantee
from dba_audit_trail
where action_name = 'GRANT ROLE'
and obj_name = 'DBA'
and timestamp >= (last_time_check_was_done)
You could also create a database trigger for that:
CREATE OR REPLACE TRIGGER TG_GRANTS_DATABASE
BEFORE GRANT ON DATABASE
DECLARE
V_NUM_GRANTEES BINARY_INTEGER;
V_GRANTEE_LIST ORA_NAME_LIST_T;
V_NUM_PRIVS BINARY_INTEGER;
V_PRIV_LIST ORA_NAME_LIST_T;
VB_AUDIT_PRIV BOOLEAN;
VB_AUDIT_GRANTEE BOOLEAN;
BEGIN
V_NUM_GRANTEES := ORA_GRANTEE (V_GRANTEE_LIST);
V_NUM_PRIVS := ORA_PRIVILEGE_LIST (V_PRIV_LIST);
-- Verify the privilege
VB_AUDIT_PRIV := FALSE;
FOR COUNTER IN 1 .. V_NUM_PRIVS
LOOP
IF V_PRIV_LIST (COUNTER) IN ('DBA') THEN
VB_AUDIT_PRIV := TRUE;
EXIT;
END IF;
END LOOP;
-- Verify the user
VB_AUDIT_GRANTEE := FALSE;
FOR COUNTER IN 1 .. V_NUM_GRANTEES
LOOP
IF V_GRANTEE_LIST (COUNTER) IN ('PUBLIC') THEN
VB_AUDIT_GRANTEE := TRUE;
EXIT;
END IF;
END LOOP;
-- Prevent the statement
-- or audit it (BEST DONE on 'AFTER GRANT ON DATABASE trigger')
IF VB_AUDIT_GRANTEE AND VB_AUDIT_PRIV THEN
RAISE_APPLICATION_ERROR(-20001,'Sorry, this can''t be done.');
END IF;
END;
This was an adaptation based on: http://examples.oreilly.com/oraclep3/individual_files/what_privs.sql

Resources