Minimize
Blogger List

Johannes Ahrends
Toad and Oracle

Ben Boise
Toad SC Discussions

Kevin Dalton
Benchmark Factory

Steven Feuerstein
PL/SQL Obsession

Devin Gallagher
Toad SC discussions

Stuart Hodgins
JProbe Discussions

  Henrik "Mauritz" Johnson
Toad Tips & Tricks on the "other" Toads
  Mark Kurtz
Toad SC discussions
  Michael Lumbard
Toad SC discussions
Daniel Norwood
Toad for Data Analysts,
Toad Extension for Visual Studio
Debbie Peabody
Toad for Data Analysts
Gary Piper
Toad Reports Manager
John Pocknell
Toad for Oracle, JProbe
Kuljit Sangha
Toad SC discussions
Bert Scalzo Indicates Oracle ACE status
Toad for Oracle, Data Modeling, Benchmarking
Jeff Smith
Toad product family
Richard To
SQL Optimization
Jim Wankowski
DB2 - LUW and z/OS
John Weathington
  Toad Data Modeler Opens in a new window
Data Modeling
 
  Real Automated Code Testing for Oracle
Quest Code Tester blog
 
Minimize
Blog Tags
toad for oracle (122)
oracle (62)
plsql (46)
sql optimization (37)
toad for data analysts (28)
code tester (19)
toad for ibm db2 (13)
automation (11)
batch optimizer (10)
virtualization (10)
schema browser (9)
toad for sql server (9)
data grid (8)
sql (8)
sql editor (8)
toad data modeler (8)
benchmark factory (7)
excel (7)
query builder (7)
report manager (7)
toad extension (7)
visual studio (7)
11g (6)
configuration (6)
freeware (6)
health check (6)
vmware (6)
connect (5)
dba module (5)
er diagrammer (5)
F4 (5)
linux (5)
refactoring (5)
spotlight (5)
unicode (5)
compare (4)
debugger (4)
export (4)
formatter (4)
make code (4)
rman (4)
strip code (4)
benchmark (3)
bfscript (3)
bulk collect (3)
code templates (3)
code xpert (3)
database browser (3)
db2 (3)
notebook (3)
oem (3)
RAC (3)
session browser (3)
speed (3)
sql optimizer (3)
toad for mysql (3)
tpc-c (3)
9.7 (2)
alert log (2)
app designer (2)
awr (2)
code insight (2)
code snippets (2)
collection (2)
compare and sync (2)
compliance (2)
data generator (2)
data warehouse (2)
database explorer (2)
database monitor (2)
explain (2)
forall (2)
ftp (2)
group execute (2)
handbook (2)
installation (2)
job scheduler (2)
multi-task (2)
nested table (2)
os command (2)
profiler (2)
recovery (2)
release history (2)
save as (2)
schema compare (2)
sql recall (2)
stats pack (2)
subversion (2)
team coding (2)
trace file browser (2)
while loop (2)
10g (1)
64 bit (1)
7zip (1)
action (1)
addm (1)
alter (1)
ansi join (1)
array (1)
ccleaner (1)
code coverage (1)
code road map (1)
CRON (1)
cursor for loop (1)
data browser (1)
data subset (1)
database probe (1)
dbms_flashback (1)
dbms_profiler (1)
ddl (1)
feuerstein (1)
filezilla (1)
flash drive (1)
flow control (1)
for loop (1)
group policy manager (1)
hints (1)
import (1)
index (1)
inheritance (1)
invoker rights (1)
ipad (1)
java (1)
latency (1)
log switch (1)
logical model (1)
ltrim (1)
master-detail browser (1)
monitor (1)
multi-select (1)
naming standards (1)
network (1)
object explorer (1)
OEBS (1)
package (1)
parser (1)
partitioning (1)
performance (1)
pragma (1)
project manager (1)
RAT (1)
revo (1)
REXEC (1)
schema report (1)
script manager (1)
search (1)
set operator (1)
sga (1)
slow (1)
sonarsource (1)
source control (1)
space projection (1)
sql monitor (1)
sql navigator (1)
sql script (1)
sql tracker (1)
sql*plus (1)
standards (1)
statistics (1)
stored procedure (1)
string parser (1)
sub-model (1)
sub-type (1)
synch (1)
synchback (1)
TELNET (1)
toad (1)
trace (1)
unit test (1)
unix (1)
usb (1)
utility (1)
v10 (1)
v9.5 (1)
version control (1)
waits (1)
workload replay (1)
workspace (1)
xml (1)
 
WELCOME, GUEST
 
 

Blogs
Toad and Database Commentaries

Toad World blogs are a mix of insightful how-tos from Quest experts as well as their commentary on experiences with new database technologies.  Have some views of your own to share?  Post your comments!  Note:  Comments are restricted to registered Toad World users.

Do you have a topic that you'd like discussed?  We'd love to hear from you.  Send us your idea for a blog topic.


Apr 13

Written by: StevenFeuersteinTW
Tuesday, April 13, 2010 5:54 AM  RssIcon

"Invoker rights, what's that?" you may be asking.

That wouldn't surprise me, greatly, though one might consider it a bit odd because the invoker rights feature of PL/SQL was added in Oracle8i - many years ago!

So I will first offer a brief overview of invoker rights, why you'd use it, how you use it. Then I will introduce one of the major challenges with invoker rights. Finally, I offer a utility that can help you overcome that challenge.

When you create a PL/SQL program unit, you can include an optional AUTHID clause. There are two forms of this clause:

AUTHID DEFINER
AUTHID CURRENT_USER

AUTHID DEFINER is the default. So these two procedures specify "definer rights"

PROCEDURE show_emp_count AUTHID DEFINER
PROCEDURE show_emp_count

And this version specifies "invoker rights":

PROCEDURE show_emp_count AUTHID CURRENT_USER

So that's the syntax. What does it do for you?

In many application environments, the code is owned by one schema (let's call it CODE_SCHEMA), and then privileges are granted to execute that code to other schemas (USER_SCHEMA).

When a program unit is created in CODE_SCHEMA with definer rights, then when a user connected to USER_SCHEMA runs that program, it runs under the privileges of CODE_SCHEMA.

When a program unit is created in CODE_SCHEMA with invoker rights, then when a user connected to USER_SCHEMA runs that program, it runs under the privileges of USER_SCHEMA. And all such privileges must be directly granted (no role-based privileges).

In other words, at the time an invoker rights program is executed, Oracle resolves all references to SQL-related database objects (tables and views, for the most part) according to the current user's privileges, and not the privileges of the owner of the program. And role-based privileges are used by Oracle with invoker rights programs.

I will step through a simple demonstration below. You are, however, probably wondering what invoker rights is good for. Invoker rights comes in very handy whenever you have a program that needs to work differently (with different tables) depending on who is running the code.

Consider Quest Code Tester for Oracle. This automated testing tool for PL/SQL is built around a test repository: 30+ tables and associated code. Usually, this repository is installed in a central schema, and then access to the repository is allowed through synonyms.

As a use of Quest Code Tester, I connect to my own development schema, and then call Code Tester programs to define and run my tests.

If Quest Code Tester relied on definer rights, then the test repository schema would need to have the authority to execute code in all the development schemas, and probably have directly granted privileges on underlying tables as well. That is a very risky test repository and most DBAs will not create such a powerful schema.

Instead, many of the packages in Quest Code Tester are defined as invoker rights. So when the developer asks Code Tester to run a test of the program in her schema, no special privileges are needed in the test repository schema. And Code Tester is not able to do anything to application data that the developer's code does not specifically allow.
In essence, with invoker rights, Oracle "reflects" back into the invoking schema to resolve references as you see below:


 
Now let's walk through a simple demonstration. I will first create a table in SCOTT with two rows:

CONNECT scott/tiger
CREATE TABLE authid_demo (n NUMBER)
/
BEGIN
   INSERT INTO
authid_demo
   VALUES (1);
   INSERT INTO authid_demo
   VALUES (2);
   COMMIT;
END;
/

I will create the "same" table in HR, but with no rows:

CONNECT hr/hr
CREATE TABLE authid_demo (n NUMBER)
/

Then in SCOTT, I create three procedures, each of which do mostly the same thing: show the number of rows in the authid_demo table.

CREATE OR REPLACE PROCEDURE proc1 AUTHID CURRENT_USER
IS
   num   PLS_INTEGER;
BEGIN
   SELECT COUNT (
*) INTO num FROM authid_demo;
   DBMS_OUTPUT.put_line ('proc 1 invoker authid_demo count = ' || num);
END;
/
CREATE OR REPLACE PROCEDURE proc2 AUTHID DEFINER
IS
   num   PLS_INTEGER;
BEGIN
   SELECT COUNT (
*) INTO num FROM authid_demo;
   DBMS_OUTPUT.put_line ('proc 2 definer authid_demo count = ' || num);
   proc1;
END;
/
CREATE OR REPLACE PROCEDURE proc3 AUTHID CURRENT_USER
IS
   num   PLS_INTEGER;
BEGIN
   SELECT COUNT (
*) INTO num FROM authid_demo;
   DBMS_OUTPUT.put_line ('proc 3 invoker authid_demo count = ' || num);
   proc1;
   proc2;
END;
/

Note that we have these two sequence of calls:

PROC3 -> PROC1
PROC3 -> PROC2 -> PROC1

and that PROC3 and PROC1 are invoker rights, while PROC2 is definer rights.

I then allow HR to run all this code and access the underlying table in SCOTT:

GRANT EXECUTE ON proc1 TO hr
/
GRANT EXECUTE ON proc2 TO hr
/
GRANT EXECUTE ON proc3 TO hr
/
GRANT SELECT ON scott.authid_demo TO hr
/

Finally, I run PROC3 - from HR:

BEGIN
   scott.proc3;
END;
/

Here's the output I see:

Line 1: proc 3 invoker authid_demo count = 0
Line 2: proc 1 invoker authid_demo count = 0
Line 3: proc 2 definer authid_demo count = 2
Line 4: proc 1 invoker authid_demo count = 2

Lines 1 and 2 demonstrate invoker rights at work: even though HR called SCOTT's PROC3 and PROC1 programs, the count of rows in authid_demo is retuned as 0, not 2.

Line 3 demonstrates definer rights: it shows the number of rows in SCOTT's authid_demo table, even though the program was called by HR.

But line 4 - now that is puzzling, isn't it? Notice that I got an answer of 2, not 0, for the count in the authid_demo table. Yet I called the same program (PROC1) that two lines earlier showed 2.

So: same code executes, but returns different answer. Very troubling, wouldn't you say?

Here's the problem: if at any point along the execution call stack (in this case, PROC3 -> PROC2 -> PROC1), a definer rights program is executed, then from that point on down the stack the "current user" is resolved by Oracle to be the owner of that definer rights program and not the currently connected user.

When PROC3 called PROC1, that was invoker rights calling invoker rights, and so the current user was HR and the procedure showed 0 rows.

When PROC3 called PROC2, Oracle reset "current user" to SCOTT. Then when PROC2 called PROC1, Oracle resolved the reference to the authid_demo table using SCOTT, and theprocedure therefore showed 2 rows.

This change in expected behavior can cause many problems in your application, ranging from raising "table or view does not exist" and "insufficient privileges" errors to returning or changing the wrong rows of data.

Assuming this is not the behavior you want, you need to make sure that all the program units executed in your call stack are all definer rights or all invoker rights, or at least that once you call a definer rights program, you only call other definer rights programs from that point on.

Fine advice (at least I think so), but how do you apply it? Call stacks in real applications can be very deep, easily a dozen or more entries. Plus, how can you even get hold of the call stack to analyze it?

First, you can call the DBMS_UTILITY.FORMAT_CALL_STACK at any point in your code, and Oracle will return a string that contains the call stack. Here's an example of the formatted call stack Oracle returns, taken from the Quest Code Tester log:

 

----- PL/SQL Call Stack -----
  object      line  object
  handle    number  name
3B6C8C64         1  anonymous block
3FA473E8      1012  package body QCTO183.QU_RUNTIME
3FA473E8      1042  package body QCTO183.QU_RUNTIME
3FA32EF8      3120  package body QCTO183.QU_ALL_OBJECTS
3FA32EF8      3138  package body QCTO183.QU_ALL_OBJECTS
3FA12F2C      2613  package body QCTO183.QU_GENERATE
3FA12F2C      3269  package body QCTO183.QU_GENERATE
3FA12F2C      3341  package body QCTO183.QU_GENERATE
3FA12F2C      3601  package body QCTO183.QU_GENERATE
3FA12F2C      6192  package body QCTO183.QU_GENERATE
3FA12F2C      8835  package body QCTO183.QU_GENERATE
3FA12F2C      9138  package body QCTO183.QU_GENERATE
3FA12F2C      9196  package body QCTO183.QU_GENERATE
3FA12F2C      9487  package body QCTO183.QU_GENERATE
4DA12F23      9737  package body QCTO183.QU_HARNESS
3BC12F2C      9800  package body QCTO183.QU_TEST
3BC12F2C     10130  package body QCTO183.QU_TEST
3B6F83F8         4  anonymous block

 

So to follow my own advice, I would now have to open each of these package specifications and check the AUTHID setting. That's rather tedious.

Perhaps there is another way. Consider the ALL_PROCEDURES data dictionary view:


 
Notice the AUTHID column. You can look up the AUTHID setting for your program unit from this view. So it seems as though you could write a program to parse the call stack and then look up the AUTHID setting for each program unit in the stack, and make sure there are no problems with  a switch from invoker rights to definer rights, and back, in that stack.

Yes, you could do that. But likely you want, because you have a real job and a real life and very little time to write such programs.

Fortunately, I don't have a "real job" (well, believe you me, they keep me very busy here at Quest, but they also more or less let me do what I want. J ) and I sure don't have a real life. My office is at home, so the boundaries between work (PL/SQL) and non-work crumbled years ago.

Well, enough about me and my life. The bottom line is that I have created a package, called authid_analysis, available in authid_analysis.pkg file of my demo.zip, that will perform precisely this analysis on your behalf.

Here's the header of the package:

CREATE OR REPLACE PACKAGE authid_analysis
IS
   FUNCTION
authid_setting (program_owner_in IN VARCHAR2
                          , program_name_in  IN VARCHAR2
                           )
      RETURN VARCHAR2;
   FUNCTION is_current_user (program_owner_in IN VARCHAR2
                           , program_name_in  IN VARCHAR2
                            )
      RETURN BOOLEAN;
   FUNCTION is_definer (program_owner_in IN VARCHAR2
                      , program_name_in  IN VARCHAR2
                       )
      RETURN BOOLEAN;
   PROCEDURE analyze_callstack (callstack_in IN VARCHAR2 DEFAULT NULL);
END
authid_analysis;

You can retrieve the AUTHID setting of a program from ALL_PROCEDURES and find out if a program is invoker rights (is_current_user) or definer rights (is_definer).

Finally, call the analyze_callstack procedure to identify possible problems, as described above. If you do not pass the call stack, analyze_callstack will call the FORMAT_CALL_STACK function for you.

You can easily integrate this package into your error logging and tracing routine, making it easy to identify possible program areas in your code. I plan to add this to Quest Error Manager as soon as I have a moment.

The authid_analysis.tst scritp will allow you run a quick test of this utility. Here's what I see:

CREATE OR REPLACE PROCEDURE proc1
   AUTHID CURRENT_USER
IS
BEGIN

   authid_analysis.analyze_callstack;
END;
/
CREATE OR REPLACE PROCEDURE proc2
IS
BEGIN

   proc1;
END;
/
CREATE OR REPLACE PROCEDURE proc3
   AUTHID CURRENT_USER
IS
BEGIN
   proc2;
END;
/
BEGIN
   proc3;
END;
/
> DEFINER      package body HR.AUTHID_ANALYSIS called by...
> CURRENT_USER procedure HR.PROC1 called by...
> DEFINER      procedure HR.PROC2 called by...
> CURRENT_USER procedure HR.PROC3 called by...
>              anonymous block

As you can see, I have a switch from invoker rights to definer rights in the call to PROC2 and that will likely cause problems.

I hope you find this utility useful.

 

Search Blog Entries