29 August 2014

5 minutes: Grant Role to Package

The EOUC (EMEA Oracle User Group Community) hosts a special session on sunday during Oracle Open World. This session contains twelve things about Oracle 12c. Each of these 12 things is hosted by a different speaker, so this means that each section is only five minutes long (Strictly guarded by Debra Lilley).
Thankfully I was chosen to be one of the speaker during this special session, very excited and also very scared. Five minutes is not a whole lot to tell the story of PL/SQL security enhancements in 12c.

This blogpost will cover my five minutes of fame.

The thing that I will cover is Code Based Access Control (or actually only a small example where you grant privileges to a package).

1. Setting the stage

For this example I will use Schema A which will contain two tables (T1 and T2) and a package (PKG).
The structure of the tables is irrelevant, and so is the actual implementation of the package.

2. The Package's Objective

The actual implementation of the package is not really relevant, what is important to know is that it would query table T1 and would manipulate some data of table T2. However it should work on schema A's table T1 and on the calling schema's table T2.
The reason that schema A has a table T2 is that it would be impossible to compile the package if table T2 was missing. Table T2 only acts as a template table in schema A.
The calling schema should have a table named T2 in order for the package to be able to work.

note: the calling schema is the schema which would call the package that schema A has defined.

The package (located in schema A) should therefor be compiled with Invoker Rights (authid current_user) as opposed to Definer Rights (authid definer).
The reference to table T1 should be fully qualified (a.t1) and the reference to table T2 should not be fully qualified (t2).
Because of the Invoker Rights specification on the package PKG the table T2 of the calling schema is used. And because of the full qualification of table T1 (a.T1) the correct table is referenced (the one in schema A).
For a calling schema to be able to use this package (PKG) - let's assume the calling schema is called B - EXECUTE privileges need to be granted to schema B

grant execute on pkg to b;

3. The Old way (< 2013) and the flaw

Before the release of Oracle 12c, only granting execute privileges on package PKG to schema B would not be sufficient.
When invoking the package:

begin
   a.pkg;
end;
there would be an exception raised because of the reference to table T1 which resides in schema A.
ORA-00942: table or view does not exist
What you needed to do was to grant privileges on schema A's table T1 as well.
grant select on t1 to b;
Now all works fine. The package can be executed from schema B, and they lived happily ever after.
So, what is the security issue here?
Not only can the package be executed from schema B, the table T1 (in schema A) can also be queried directly without using the package. What if there are columns in table T1 that contain sensitive information?

4. Fixing the flaw

The solution is to grant privileges to the package and not to the user.
First of all: revoke the select privileges on schema A's T1 from schema B

revoke select on t1 from b
Next create a role and grant the select privileges on schema A's table T1 to that role. What you couldn't do before was grant a role to a package, but now you can.
create role only_this_role;

grant select on a.t1 to only_this_role;

grant only_this_role to package a.pkg;
And that's it.
The execute privileges on the package still exists of course otherwise schema B wouldn't be able to execute the package.
Table T1 (in schema A) can not be called directly by schema B any longer.
Now only the package can make calls to table T1.
This adheres to the concept of least privileges.

3 comments:

  1. Write a PL/SQL function that returns the list of dates between two dates (say start_date and end_date) return the list of dates but with the date as index of the type and holiday_name or 'Working Day' as the value of the element. The output should be as follows:
    dates_array('01-Jan-2015') => 'New Year'
    dates_array('02-Jan-2015') => 'Working Day'
    dates_array('03-Jan-2015') => 'Saturday'
    dates_array('04-Jan-2015') => 'Sunday'
    dates_array('05-Jan-2015') => 'Working Day'
    dates_array('06-Jan-2015') => 'Working Day'
    dates_array('07-Jan-2015') => 'Working Day'
    dates_array('08-Jan-2015') => 'Working Day'
    dates_array('09-Jan-2015') => 'Working Day'
    dates_array('10-Jan-2015') => 'Saturday'
    dates_array('11-Jan-2015') => 'Sunday'
    dates_array('12-Jan-2015') => 'Working Day'
    dates_array('13-Jan-2015') => 'Working Day'
    dates_array('14-Jan-2015') => 'Working Day'
    dates_array('15-Jan-2015') => 'Pongal'
    dates_array('16-Jan-2015') => 'Working Day'
    dates_array('17-Jan-2015') => 'Saturday'
    dates_array('18-Jan-2015') => 'Sunday'
    dates_array('19-Jan-2015') => 'Working Day'
    dates_array('20-Jan-2015') => 'Working Day'
    dates_array('21-Jan-2015') => 'Working Day'
    dates_array('22-Jan-2015') => 'Working Day'
    dates_array('23-Jan-2015') => 'Working Day'
    dates_array('24-Jan-2015') => 'Saturday'

    ReplyDelete
    Replies
    1. and what does this have to do with Granting Roles to Packages? Answer: Nothing... and No, I will not do your homework.

      Delete
  2. What system catalog views show the roles granted to a package?
    i.e. how can I check to see if these role grants are already in place?
    I do not see them in DBA_ROLE_PRIVS or DBA_TAB_PRIVS.

    ReplyDelete