| Oracle9i Application Developer's Guide - Fundamentals Release 2 (9.2) Part Number A96590-01 |
|
This chapter explains how to implement application security policies. Topics in this chapter include:
Application context allows you to write applications which draw upon certain aspects of a user's session information. It provides a way to define, set, and access attributes that an application can use to enforce access control--specifically, fine-grained access control.
Most applications contain information about the basis on which access is to be limited. In an order entry application, for example, customers would be limited to access their own orders (ORDER_NUMBER) and customer number (CUSTOMER_NUMBER). These can be used as security attributes.
Consider a user running a Human Resource application. Part of the application's initialization process is to determine the kind of responsibility that the user can assume, based on the user's identity. This responsibility ID becomes part of the Human Resource application context; it will affect what data the user can access throughout the session.
This section explains the use of application context. It includes:
Application context provides important security features:
Each application can have its own context with its own attributes. Suppose, for example, you have three applications: General Ledger, Order Entry, and Human Resources. You can specify different attributes for each application. Thus,
SET_OF_BOOKS and TITLE.CUSTOMER_NUMBER.ORGANIZATION_ID, POSITION, and COUNTRY.In each case, you can adapt the application context to your precise security needs.
Suppose you have a General Ledger application, which has access control based upon the set of books being used. If a user accessing this application changes the set of books he is working on from 01 to 02, the application context can ensure that:
The validation function can check application metadata tables to make this determination and ensure that the attributes in combination are in line with the overall security policy. To prevent users from changing a context attribute without the above security validation, Oracle ensures that an attribute can be changed only by the designated package which implements the context.
Oracle9i provides a built-in application context namespace, USERENV, which provides access to predefined attributes. These attributes are session primitives--information which the database captures regarding a user's session. For example, the IP address from which a user connected, the username, and a proxy username (in cases where a user connection is proxied through a middle tier), are all available as predefined attributes through the USERENV application context.
Predefined attributes can be very useful for access control. For example, if you are using a three-tier application which creates lightweight user sessions through OCI or thick JDBC, you can access the PROXY_USER attribute in the USERENV application context to determine whether the user's session was created by a middle tier application. Your policy function could allow a user to access data only for connections where the user is proxied. If the user is not proxied (that is, when the user connects directly to the database), the user would not be able to access any data.
While you can use the PROXY_USER attribute within VPD to ensure that users only access data through a particular middle-tier application, a different approach would be to develop a secure application role. Rather than have each policy ensure that the user accesses the database by being proxied through HRAPPSERVER, you could have the secure application role enforce this.
Although predefined attributes can be accessed through the USERENV application context, they cannot not be changed. They are listed in Table 12-1.
Use the following syntax to return information about the current session.
SYS_CONTEXT('userenv', 'attribute')
|
Note: The USERENV application context namespace is intended to replace the USERENV function provided in earlier database releases.
|
| See Also:
|
Many applications store attributes used for fine-grained access control within a database metadata table that they use for access control. For example, an EMPLOYEES table could include cost center, title, signing authority, and other information useful for fine-grained access control. However, many organizations centralize user information and user management in an LDAP-based directory such as Oracle Internet Directory. These organizations also wish to centralize the information about users that is used for access control. Application context attributes can be stored in Oracle Internet Directory and assigned to one or more enterprise users. They can be retrieved automatically upon login for an enterprise user, and used to initialize an application context.
To simplify the implementation of a security policy, you have the option of using application context within a fine-grained access control function.
|
Note: Using application context with fine-grained access control is called Virtual Private Database (VPD). |
Application context can be used in the following ways with fine-grained access control:
Accessing an application context inside your fine-grained access control policy function is like writing down an often-used phone number and posting it next to your phone, where you can find it easily--rather than looking it up every time you need it.
For example, suppose you base access to the ORDERS_TAB table upon customer number. Rather than querying the customer number for a logged-in user each time you need it, you could store the number in the application context. In this way, the customer number is available when you need it.
Application context is especially helpful if your security policy is based upon multiple security attributes. For example, a policy function which bases a predicate on four attributes (such as employee number, cost center, position, spending limit) would have to execute multiple subqueries to retrieve this information. If all of this data is already available through application context, then performance will be much faster.
You can use application context to return the correct predicate--that is, the correct security policy.
Consider an order entry application which enforces the rules, "customers only see their own orders, and clerks see all orders for all customers." These are two different policies. You could define an application context with a position attribute, and this attribute could be accessed within the policy function to return the correct predicate, depending on the value of the attribute. Thus, you can enable a user in the Clerk position to retrieve all orders, but a user in the Customer position to see his own records only.
To design a fine-grained access control policy to return a specific predicate for an attribute, access the application context within the function that implements the policy. For example, to limit customers to seeing their own records only, use fine-grained access control to dynamically modify the user's query from this:
SELECT * FROM Orders_tab
to this:
SELECT * FROM Orders_tab WHERE Custno = SYS_CONTEXT ('order_entry', 'cust_num');
Continuing with the example above, suppose you have 50,000 customers, and you do not want to have a different predicate returned for each customer. Customers all share the same policy. That is, they can only see their own orders. It is merely their customer numbers which are different.
Using application context, you can return one predicate within a policy function which applies to 50,000 customers. As a result, there is one shared cursor which nonetheless executes differently for each customer, because the customer number is evaluated at execution time. This value is, of course, different for every customer. Use of application context in this case provides optimum performance, as well as fine-grained security.
Note that the SYS_CONTEXT function works much like a bind variable, but only if the SYS_CONTEXT arguments are constants.
Applications may have differing user models, but you may want to use Virtual Private Database (VPD) to limit access by user. Whether the user is a database user or an application user unknown to the database, Oracle provides different ways in which applications can enforce per-user fine-grained access control.
For applications in which the application users are also database users, VPD enforcement is relatively simple; users connect to the database, and the application can set up per-session application contexts. Each session is initiated under a different username, so that it is simple to enforce different fine-grained access control conditions for users Jane and John. This is also possible with use of proxy authentication, since each "lightweight" session in OCI or thick JDBC is still a distinct database session, and can have its own application context.
Since proxy authentication can be integrated with Enterprise User Security, user roles can be retrieved from Oracle Internet Directory, as well as other attributes that can be used for VPD enforcement.
For applications in which a single user (for example, One Big Application User) connects to the database on behalf of all users, per-user fine-grained access control is still possible. An application developer can create a context attribute to represent the application user (for example, realuser). While all database sessions (and thus all audit records) are initiated as One Big Application User, each session can nonetheless have attributes that vary, depending on who the real user is. This model works best for applications with a limited number of users where there is no requirement for session reuse. Of course, each session, from the database standpoint, is created as the same database user, so that the ability to use roles, database auditing, and others is greatly diminished for reasons previously enumerated.
Web-based applications typically have hundreds if not thousands of users, and the web is stateless. There may be a persistent connection to the database (to support data retrieval for a number of user requests), but these connections are not specific to each web-based user. Web-based applications typically set up and reuse connections instead of having different sessions for each user, to provide scalability. For example, web user Jane and Ajit connect to a middle tier application, which establishes a session in the database used by the application on behalf of both users. Typically, neither Jane nor Ajit are known to the database. The application is responsible for switching the username on the connection, so that, at any given time, it's either Jane or Ajit using the session.
Oracle9i VPD capabilities facilitate connection pooling by allowing multiple connections to access one or more global application contexts, instead of setting up an application context for each distinct user session.
Applications use a CLIENT_IDENTIFIER (which could be an individual application username, or a group) to reference the global application context. Global application contexts provide additional flexibility for web-based applications to use Virtual Private Database, as well as enhanced performance through reuse of common application contexts among multiple sessions instead of setting up per-session application contexts. The CLIENT_IDENTIFIER is also viewable in the user session and accessible in the USERENV naming context.
The use of a CLIENT_IDENTIFIER thus functions as an application user proxy, since the CLIENT_IDENTIFIER can be used to capture the 'application username.' The ability to pass a CLIENT_IDENTIFIER to the database for use with global application context is supported in OCI, thick JDBC, and thin JDBC. For OCI-based connections, a change in CLIENT_IDENTIFIER is automatically piggybacked on the next OCI call, for additional performance benefits.
Application user proxy authentication can be used with global application context for additional flexibility and high performance in building applications. For example, suppose a web-based application that provides information to business partners has three types of users: gold partner, silver partner, and bronze partner, representing different levels of information available. Instead of each user having his own session -- with individual application contexts -- set up, the application could set up global application contexts for gold partner, silver partner, or bronze partner and use the client identifier to point the session at the correct context, in order to retrieve the appropriate type of data. The application need only initialize the three global contexts once, and use the client identifier to access the correct application context to limit data access. This provides performance improvements through session reuse, and through accessing global application contexts set up once, instead of having to initialize application contexts for each session individually.
Developers implementing Virtual Private Database (VPD) can use the DBMS_RLS package to apply security policies to tables and views. Also, Developers can use the CREATE CONTEXT command to create application contexts.
Alternatively, developers can use the Oracle Policy Manager graphical user interface, accessed from Oracle Enterprise Manager, to apply security policies to schema objects, such as tables and views, and to create application contexts. Oracle Policy Manager provides an easy-to-use interface to manage security policies and application contexts, and therefore makes VPD easier to develop.
Oracle Policy Manager is the administration tool for Oracle Label Security. Oracle Label Security provides a functional, out-of-the-box VPD policy which enhances your ability to implement row-level security. It supplies an infrastructure--a label-based access control framework--whereby you can specify labels for users and data. It also enables you to create one or more custom security policies to be used for label access decisions. You can implement these policies without any knowledge of a programming language. There is no need to write additional code; in a single step you can apply a security policy to a given table. In this way, Oracle Label Security provides a straightforward, efficient way to implement fine-grained security policies using data labeling technology. Finally, the structure of Oracle Label Security labels provides a degree of granularity and flexibility which cannot easily be derived from the application data alone. Oracle Label Security is thus a generic solution which can be used in many different circumstances.
To create VPD policies, users must provide the schema name, table (or view) name, policy name, the function name that generates the predicate, and the statement types to which the policy applies (that is, SELECT, INSERT, UPDATE, DELETE). Oracle Policy Manager then executes the function DBMS_RLS.ADD_POLICY. You create an application context by providing the name of the context and the package that implements the context.
To use application context, you perform the following tasks:
Begin by creating a PL/SQL package with functions that set the context for your application. This section presents an example for creating the PL/SQL package, followed by a discussion of SYS_CONTEXT syntax and behavior.
|
Note: A login trigger can be used because the user's context (information such as |
The following example creates the package app_security_context.
CREATE OR REPLACE PACKAGE App_security_context IS PROCEDURE Set_empno; END; CREATE OR REPLACE PACKAGE BODY App_security_context IS PROCEDURE Set_empno IS Emp_id NUMBER; BEGIN SELECT Empno INTO Emp_id FROM Emp_tab WHERE Ename = SYS_CONTEXT('USERENV', 'SESSION_USER'); DBMS_SESSION.SET_CONTEXT('app_context', 'empno', Emp_id); END; END;
The syntax for this function is:
SYS_CONTEXT ('namespace', 'attribute', [length])
This function returns the value of attribute as defined in the package currently associated with the context namespace. It is evaluated once for each statement execution, and is treated like a constant during type checking for optimization. You can use the pre-defined namespace USERENV to access primitive contexts such as userid and NLS parameters.
|
Note: If you try to execute SYS_CONTEXT in a parallel query environment, you will receive a query error. See Using SYS_CONTEXT in a Parallel Query. |
| See Also:
"Providing Access to Predefined Attributes Through the USERENV Namespace" Oracle9i SQL Reference for details about attributes |
During a session in which you expect a change in policy between executions of a given query, that query must use dynamic SQL. You must use dynamic SQL because static SQL and dynamic SQL parse statements differently.
Consider a situation in which policy A is in force when you compile a SQL statement--and then you switch to policy B and execute the statement. With static SQL, policy A remains in force: the statement is parsed at compile time and not reparsed upon execution. With dynamic SQL, however, the statement is parsed upon execution, and so the switch to policy B is carried through.
For example, consider the following policy:
EMPLOYEE_NAME = SYS_CONTEXT ('userenv', 'session_user')
The policy "Employee name matches database user name" is represented in the form of a SQL predicate: the predicate is basically a policy. If the predicate changes, the statement must be reparsed in order to produce the correct result.
If SYS_CONTEXT is used inside a SQL function which is embedded in a parallel query, the function cannot pick up the application context. This is true because the application context exists only in the user session. To use these features in combination, you must call SYS_CONTEXT directly from the query.
Consider a user-defined function within a SQL statement, which sets the user's ID to 5:
CREATE FUNC proc1 AS RETURN NUMBER; BEGIN IF SYS_CONTEXT ('hr', 'id') = 5 THEN RETURN 1; ELSE RETURN 2; END END;
Now consider the statement:
SELECT * FROM EMP WHERE proc1( ) = 1;
If this statement is run as a single query (that is, if one process is used to run the entire query), there will be no problem.
However, if this statement is run as a parallel query, the parallel execution servers (query slave processes) do not have access to the user session which contains the application context information. The query will not produce the expected results.
By contrast, if you use the SYS_CONTEXT function within a query, there is no problem. For example,
SELECT * FROM EMP WHERE SYS_CONTEXT ('hr', 'id') = 5;
In this way, it works like a bind variable: the query coordinator can access the application context information and pass it on to the parallel execution servers.
When you execute a statement, Oracle9i takes a snapshot of the entire application context being set up by SYS_CONTEXT. Within the duration of a query, the context remains the same for all fetches of the query.
If you (or a function) attempt to change the context within a query, the change will not take effect in the current query. In this way, SYS_CONTEXT enables you to store variables in a session.
To perform this task, use the CREATE CONTEXT statement. Each context must have a unique attribute and belong to a namespace. That is, context names must be unique within the database, not just within a schema. Contexts are always owned by the schema SYS.
For example:
CREATE CONTEXT order_entry USING oe_context;
where order_entry is the context namespace, and oe_context is the trusted package that can set attributes in the context namespace.
After you have created the context, you can set or reset the context attributes by using the DBMS_SESSION.SET_CONTEXT package. The values of the attributes you set remain either until you reset them, or until the user ends the session.
You can only set the context attributes inside the trusted procedure you named in the CREATE CONTEXT statement. This prevents a malicious user from changing context attributes without proper attribute validation.
Alternatively, you can use the Oracle Policy Manager graphical user interface to create a context and associate it with a PL/SQL package. Oracle Policy Manager, accessed from Oracle Enterprise Manager, enables you to apply policies to database objects and create application contexts. It also can be used to create and manage Oracle Label Security policies.
Always use an event trigger on login to pull session information into the context. This sets the user's security-limiting attributes for the database to evaluate, and thus enables it to make the appropriate security decisions.
Other considerations come into play if you have a changing set of books, or if positions change constantly. In these cases, the new attribute values may not be picked up right away, and you must force a cursor reparse to pick them up.
Now that you have set up the context and the PL/SQL package, you can go ahead and have your policy functions use the application context to make policy decisions based on different context values.
This section provides three examples that use application context within a fine-grained access control function.
This example uses application context to implement the policy, "Customers can see their own orders only."
This example guides you through the following steps in building the application:
The procedure in this example assumes a one-to-one relationship between users and customers. It finds the user's customer number (Cust_num), and caches the customer number in the application context. You can later refer to the cust_num attribute of your order entry context (order_entry_ctx) inside the security policy function.
Note that you could use a login trigger to set the initial context.
Create the package as follows:
CREATE OR REPLACE PACKAGE apps.oe_ctx AS PROCEDURE set_cust_num ; END; CREATE OR REPLACE PACKAGE BODY apps.oe_ctx AS PROCEDURE set_cust_num IS custnum NUMBER; BEGIN SELECT cust_no INTO custnum FROM customers WHERE username = SYS_CONTEXT('USERENV', 'session_user'); /* SET cust_num attribute in 'order_entry' context */ DBMS_SESSION.SET_CONTEXT('order_entry', 'cust_num', custnum); DBMS_SESSION.SET_CONTEXT('order_entry', 'cust_num', custnum); END set_cust_num; END;
|
Note: This example does not treat error handling. You can access predefined attributes--such as session user--by using For more information, see Oracle9i SQL Reference |
Create an application context by entering:
CREATE CONTEXT Order_entry USING Apps.Oe_ctx;
Alternatively, you can use Oracle Policy Manager to create an application context.
Access the application context inside the package that implements the security policy on the database object.
|
Note: You may need to set up the following data structures for certain examples to work: CREATE PACKAGE Oe_security AS FUNCTION Custnum_sec (D1 VARCHAR2, D2 VARCHAR2) RETURN VARCHAR2; END; |
The package body appends a dynamic predicate to SELECT statements on the ORDERS_TAB table. This predicate limits the orders returned to those of the user's customer number by accessing the cust_num context attribute, instead of a subquery to the customers table.
CREATE OR REPLACE PACKAGE BODY Oe_security AS /* limits select statements based on customer number: */ FUNCTION Custnum_sec (D1 VARCHAR2, D2 VARCHAR2) RETURN VARCHAR2 IS D_predicate VARCHAR2 (2000) BEGIN D_predicate = 'cust_no = SYS_CONTEXT("order_entry", "cust_num")'; RETURN D_predicate; END Custnum_sec; END Oe_security;
Create the policy as follows:
|
Note: You may need to set up the following data structures for certain examples to work: CONNECT sys/change_on_install AS sysdba; CREATE USER secusr IDENTIFIED BY secusr; |
DBMS_RLS.ADD_POLICY ('scott', 'orders_tab', 'oe_policy', 'secusr', 'oe_security.custnum_sec', 'select')
This statement adds a policy named OE_POLICY to the ORDERS_TAB table for viewing in schema SCOTT. The SECUSR.OE_SECURITY.CUSTNUM_SEC function implements the policy, is stored in the SECUSR schema, and applies to SELECT statements only.
Now, any select statement by a customer on the ORDERS_TAB table automatically returns only that customer's orders. In other words, the dynamic predicate modifies the user's statement from this:
SELECT * FROM Orders_tab;
to this:
SELECT * FROM Orders_tab WHERE Custno = SYS_CONTEXT('order_entry','cust_num');
Note the following with regard to this example:
custnum_sec function to return different predicates based on the user's position context value.SELECT * FROM Orders_tab WHERE Custno = SYS_CONTEXT('order_entry', 'cust_num')
This is fully parsed and optimized, but the evaluation of the user's CUST_NUM attribute value for the ORDER_ENTRY context takes place at execution. This means that you get the benefit of an optimized statement which executes differently for each user who executes the statement.
| See Also:
Compare and contrast this example, which uses an application context within the dynamically generated predicate, with "How Fine-Grained Access Control Works", which uses a subquery in the predicate |
This example uses application context to control user access by way of a Human Resources application. It guides you through the following three tasks, each of which is described more fully below.
In this example, assume that the application context for the Human Resources application is assigned to the HR_CTX namespace.
Create a PL/SQL package with a number of functions that set the context for the application
APPS is the schema owning the package.
CREATE OR REPLACE PACKAGE BODY apps.hr_sec_ctx IS /* function to set responsibility id */ PROCEDURE set_resp_id (respid NUMBER) IS BEGIN /* validate respid based on primitive and other context */ /* validate_respid (respid); */ /* set resp_id attribute under namespace 'hr_ctx'*/ DBMS_SESSION.SET_CONTEXT('hr_ctx', 'resp_id', respid); END set_resp_id; /* function to set organization id */ PROCEDURE set_org_id (orgid NUMBER) IS BEGIN /* validate organization ID */ /* validate_org_id(orgid); /* /* set org_id attribute under namespace 'hr_ctx' */ DBMS_SESSION.SET_CONTEXT('hr_ctx', 'org_id', orgid); END set_org_id; /* more functions to set other attributes for the HR application */ END hr_sec_ctx;
For example:
CREATE CONTEXT Hr_ctx USING Apps.Hr_sec_ctx;
Suppose that the execute privilege on the package HR_SEC_CTX has been granted to the schema running the application. Part of the script will make calls to set various attributes of the HR_CTX context. Here, we do not show how the context is determined. Normally, it is based on the primitive context or other derived context.
APPS.HR_SEC_CTX.SET_RESP_ID(1); APPS.HR_SEC_CTX.SET_ORG_ID(101);
The SYS_CONTEXT function can be used for data access control based on this application context. For example, the base table HR_ORGANIZATION_UNIT can be secured by a view that restricts access to rows based on attribute ORG_ID:
|
Note: You may need to set up data structures for certain examples to work: CREATE TABLE hr_organization_unit (organization_id NUMBER); |
CREATE VIEW Hr_organization_secv AS SELECT * FROM hr_organization_unit WHERE Organization_id = SYS_CONTEXT('hr_ctx','org_id');
This example illustrates use of the following security features in Oracle9i:
In this example, we associate a security policy with the table called DIRECTORY which has the following columns:
| Column | Description |
|---|---|
|
|
identification number for each employee |
|
|
employee identification number for the manager of each employee |
|
|
position of the employee in the corporate hierarchy |
The security policy associated with this table has two elements:
MGRID for a specific EMPNO. To implement this, we create a definer's right package in the Human Resources schema (HR) to perform SELECT on the table.EMPNO and application context.EMPNO by using a logon trigger.|
Note: In this example, we grant |
CONNECT system/manager AS sysdba GRANT CONNECT,RESOURCE,UNLIMITED TABLESPACE,CREATE ANY CONTEXT, CREATE PROCEDURE, CREATE ANY TRIGGER TO HR IDENTIFIED BY HR; CONNECT hr/hr; CREATE TABLE Directory (Empno NUMBER(4) NOT NULL, Mgrno NUMBER(4) NOT NULL, Rank NUMBER(7,2) NOT NULL); CREATE TABLE Payroll (Empno NUMBER(4) NOT NULL, Name VARCHAR(30) NOT NULL ); /* seed the tables with a couple of managers: */ INSERT INTO Directory VALUES (1, 1, 1.0); INSERT INTO Payroll VALUES (1, 'KING'); INSERT INTO Directory VALUES (2, 1, 5); INSERT INTO Payroll VALUES (2, 'CLARK'); /* Create the sequence number for EMPNO: */ CREATE SEQUENCE Empno_seq START WITH 5; /* Create the sequence number for RANK: */ CREATE SEQUENCE Rank_seq START WITH 100; CREATE OR REPLACE CONTEXT Hr_app USING Hr.Hr0_pck; CREATE OR REPLACE CONTEXT Hr_sec USING Hr.Hr1_pck; CREATE or REPLACE PACKAGE Hr0_pck IS PROCEDURE adjustrankby1(Empno NUMBER); END; CREATE or REPLACE PACKAGE BODY Hr0_pck IS /* raise the rank of the empno by 1: */ PROCEDURE Adjustrankby1(Empno NUMBER) IS Stmt VARCHAR2(100); BEGIN /*Set context to indicate application state */ DBMS_SESSION.SET_CONTEXT('hr_app','adjstate',1); /* Now we can issue DML statement: */ Stmt := 'UPDATE SET Rank := Rank +1 FROM Directory d WHERE d.Empno = ' || Empno; EXECUTE IMMEDIATE STMT; /* Re-set application state: */ DBMS_SESSION.SET_CONTEXT('hr_app','adjstate',0); END; END; CREATE or REPLACE PACKAGE hr1_pck IS PROCEDURE setid; END; / /* Based on userid, find EMPNO, and set it in application context */ CREATE or REPLACE PACKAGE BODY Hr1_pck IS PROCEDURE setid IS id NUMBER; BEGIN SELECT Empno INTO id FROM Payroll WHERE Name = SYS_CONTEXT('userenv','session_user') ; DBMS_SESSION.SET_CONTEXT('hr_sec','empno',id); DBMS_SESSION.SET_CONTEXT('hr_sec','appid',id); EXCEPTION /* For purposes of demonstration insert into payroll table / so that user can continue on and run example. */ WHEN NO_DATA_FOUND THEN INSERT INTO Payroll (Empno, Name) VALUES (Empno_seq.NEXTVAL, SYS_CONTEXT('userenv','session_user')); INSERT INTO Directory (Empno, Mgrno, Rank) VALUES (Empno_seq.CURRVAL, 2, Rank_seq.NEXTVAL); SELECT Empno INTO id FROM Payroll WHERE Name = sys_context('userenv','session_user') ; DBMS_SESSION.SET_CONTEXT('hr_sec','empno',id); DBMS_SESSION.SET_CONTEXT('hr_sec','appid',id); WHEN OTHERS THEN NULL; /* If this is to be fired via a "logon" trigger, / you need to handle exceptions if you want the user to continue / logging into the database. */ END; END; GRANT EXECUTE ON Hr1_pck TO public; CONNECT system/manager AS sysdba CREATE OR REPLACE TRIGGER Databasetrigger AFTER LOGON ON DATABASE BEGIN hr.Hr1_pck.Setid; END; /* Creates the package for finding the MGRID for a particular EMPNO using definer's right (encapsulated privileges). Note that users are granted EXECUTE privileges only on this package, and not on the table (DIRECTORY) it is querying. */ CREATE or REPLACE PACKAGE hr2_pck IS FUNCTION Findmgr(Empno NUMBER) RETURN NUMBER; END; CREATE or REPLACE PACKAGE BODY hr2_pck IS /* insert a new employee record: */ FUNCTION findmgr(empno number) RETURN NUMBER IS Mgrid NUMBER; BEGIN SELECT mgrno INTO mgrid FROM directory WHERE mgrid = empno; RETURN mgrid; END; END; CREATE or REPLACE FUNCTION secure_updates(ns varchar2,na varchar2) RETURN VARCHAR2 IS Results VARCHAR2(100); BEGIN /* Only allow updates when designated application has set the session state to indicate we are inside it. */ IF (sys_context('hr_sec','adjstate') = 1) THEN results := 'mgr = SYS_CONTEXT("hr_sec","empno")'; ELSE results := '1=2'; END IF; RETURN Results; END; /* Attaches fine-grained access policy to all update operations on hr.directory */ CONNECT system/manager AS sysdba; BEGIN DBMS_RLS.ADD_POLICY('hr','directory_u','secure_update','hr', 'secure_updates','update',TRUE,TRUE); END;
In many application architectures, the middle tier application is responsible for managing session pooling for application users. That is, users authenticate themselves to the application, which uses a single identity to log into the database and maintains all the connections. In this environment, it is not possible to maintain application attributes using session-dependent secure application context because of the sessionless model of the application.
Another scenario is when a user is connected to the database through an application (such as Oracle Forms) which then spawns other applications (such as Oracle Reports) to connect to the database. These applications may need to share the session attributes such that they appear to be sharing the same database session.
Global application context is a type of secure application context that can be shared among trusted sessions. In addition to driving the enforcement of the fine-grained access control policies, applications (especially middle-tier products) can use this support to manage application attributes securely and globally.
|
Note: The public Java classes AppCtxManager and AppCtxMessages are exposed in package oracle.security.rdbms.appctx. This API provides a centralized location to store the user's application context. These classes are more fully described in Oracle9i Supplied Java Packages Reference. Related information can also be found in Oracle9i Supplied PL/SQL Packages and Types Reference. FA |
The DBMS_SESSION interface for managing application context has a client identifier for each application context. In this way, application context can be managed globally, yet each client sees only his or her assigned application context. The following interfaces in DBMS_SESSION enable the administrator to manage application context in client sessions:
The middle-tier application server can use SET_CONTEXT to set application context for a specific client ID. Then, when assigning a database connection to process the client request, the application server needs to issue a SET_IDENTIFIER to denote the ID of the application session. From then on, every time the client invokes SYS_CONTEXT, only the context that was associated with the set identifier is returned. In other words, the application server uses SET_IDENTIFIER to associate the database session with a particular user or a group. Then, the CLIENT_IDENTIFIER is an attribute of the session and can be viewed in session information. Also, CLIENT_IDENTIFIER is the key to accessing the global application context. For example, suppose a web-based application that provides information to business partners has three types of users: gold partner, silver partner, and bronze partner. These users represent different levels of available information. Instead of each user having their own setup session with application contexts, the application could set up global application contexts for gold partner, silver partner, and bronze partner. Afterwards, one can do the following:
SET_IDENTIFIER to set a particular session to gold partner, silver partner, or bronze partner.The application need only initialize the three global contexts once, and use CLIENT_IDENTIFIER to access the correct application context to limit data access. This provides performance improvements through session reuse, and through accessing global application contexts setup once, instead of having to initialize application contexts for each session.
For an application context accessed globally, the scenario is as follows:
12345 to client SCOTT. It then issues the following statement to indicate that, for this client identifier, there is an application context RESPONSIBILITY with a value of 13 in the HR namespace.
DBMS_SESSION.SET_CONTEXT( 'HR', 'RESPONSIBILITY' , '13', 'SCOTT', '12345' );
Note that HR must be a global context namespace created as follows:
CREATE CONTEXT hr USING hr.init ACCESSED GLOBALLY;
APPSMGR to establish a connection to database, the following command should be issued when client SCOTT is assigned to a new database session to indicate identity:
DBMS_SESSION.SET_IDENTIFIER('12345');
SYS_CONTEXT('HR','RESPONSIBILITY') call, the database engine will match the client identifier 12345 to the global context, and return the value 13.DBMS_SESSION.CLEAR_IDENTIFIER( );
After the client identifier in a session is clear, it takes on a NULL value, implying that any subsequent SYS_CONTEXT call will only retrieve application context with a NULL client identifier, until the client identifier is set again using the SET_IDENTIFIER interface.
For a proxy authentication application, the scenario is as follows:
CREATE CONTEXT hr USING hr.init ACCESSED GLOBALLY;
HR application server (AS) starts up and establishes multiple connections to the HR database as user APPSMGR.SCOTT logs on to the HR application server.SCOTT into the application.12345, for this connection.SCOTT's browser as part of a cookie or maintained by AS.
HR.INIT package, which issues:
DBMS_SESSION.SET_CONTEXT( 'hr', 'id', 'scott', 'APPSMGR', 12345 ); DBMS_SESSION.SET_CONTEXT( 'hr', 'dept', 'sales', 'APPSMGR', 12345 );
DBMS_SESSION.SET_IDENTIFIER( 12345 );
SYS_CONTEXT calls within this database session will return application context values belonging to the client session only. For example, SYS_CONTEXT('hr','id') will return the value SCOTT.DBMS_SESSION.CLEAR_IDENTIFIER ( );
Note that even if another database user (ADAMS) had logged into the database, he cannot access the global context set by AS because AS has specified that only the application with logged in user APPSMGR can see it. If AS has used the following, then any user session with client ID set to 12345 can see the global context.
DBMS_SESSION.SET_CONTEXT( 'hr', 'id', 'scott', NULL , 12345 ); DBMS_SESSION.SET_CONTEXT( 'hr', 'dept', 'sales', NULL , 12345 );
This approach enables different users to share the same context.
The users, however, should be aware of the security implication of different settings of the global context. Basically, NULL in the username means that any user can access the global context. A NULL client ID in the global context means that only a session with an uninitialized client ID can access the global context.
Users can query the client identifier set in the session as follows:
SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER')
The DBA can see which sessions have the client identifier set by querying the V$SESSION view's CLIENT_IDENTIFIER and USERNAME.
When a user wants to see how much global context area (in bytes) is being used, she can use SYS_CONTEXT('USERENV','GLOBAL_CONTEXT_MEMORY')
| See Also:
Oracle9i Supplied PL/SQL Packages and Types Reference Oracle9i JDBC Developer's Guide and Reference and Oracle Call Interface Programmer's Guide for client identifier information |
This feature lets you specify a special type of namespace that accepts initialization of attribute values from external resources. This enhances performance and enables the automatic propagation of attributes from one session to the other. For example, many organizations want to manage user information centrally, in an LDAP-based directory. Oracle9i Enterprise User Security feature supports centralized user and authorization management in Oracle Internet Directory. However, there may be additional attributes an application wishes to retrieve from LDAP to use for VPD enforcement:
The ability to initialize application context from external sources such as LDAP helps organizations leverage existing information they have for VPD enforcement, that is centrally managed, without requiring replication or duplication of this information in database tables.
This section contains these topics:
In some situations it is desirable to obtain default values from users. These default values may serve as hints or preferences initially, and may become trusted context after the values are validated. Similarly, clients may want a convenient way to initialize some default values, and then rely on a login event trigger or applications to validate the values.
For job queues, administrators may expect the job submission routine to record all the context being set at the time the job is submitted, and restore it when executing the batched job. To maintain the integrity of context, job queues cannot bypass the designated PLSQL package to set the context. Rather, externally initialized application context accepts initialization of context values from the job queue process.
Whereas automatic propagation of context to a remote session may create security problems, developers or administrators can effectively handle this new type of context that takes default values from resources other than the designated PLSQL procedure. In addition, performance is enhanced because this feature provides an extensible interface for the OCI client to bundle more information to the server in one OCISessionBegin() call.
In addition to using the designated trusted package, externally initialized application context can also accept initialization of attributes and values through external resources such as an OCI interface, a job queue process, or a database link. It provides:
Although this new type of namespace can be initialized by any client program using OCI, there are login event triggers that can verify the values. It is up to the application to interpret and trust the values of the attributes.
Note that with this feature, the middle-tier server can actually initialize context values on behalf of database users. Context attributes are propagated for the remote session at initiation time, and the remote database accepts the values if the namespace is externally initialized.
Externally initialized application context is especially useful for cases in which users are not known to the database. In these situations, the application typically connects as a single database user, and all actions are taken as that user. Since all user sessions are created as the same user, this security model normally makes it very difficult, if not impossible, to use the Virtual Private Database capability to achieve per user or per customer data separation. However, these applications can use the client identifier as an application user proxy. In this way, the application uses the client identifier to proxy the "real" application user name to the database.
This approach has several advantages. With application user proxy, the sessions can be reused by multiple users merely by changing the client identifier (which here is employed to capture the name of the real application user). This avoids the overhead of setting up a separate session and separate attributes for the user, and enables reuse of sessions by the application merely by changing the client identifier (to represent the new application user name). When a client changes the client identifier, the change is piggybacked on the next OCI (or thick JDBC) call, for additional performance gains. Application user proxy (via client identifier) is available in available in OCI, thick JDBC, and thin JDBC.
Suppose, for example, that user Daniel connects to a Web Expense application. Daniel is not a database user, he is a typical Web Expense application user. The application sets up a global application context for a typical web user and sets DANIEL as the client identifier. Daniel completes his Web Expense form and exits the application. Ajit now connects to the Web Expense application. Instead of setting up a new session for Ajit, the application reuses the session that currently exists for Daniel, merely by changing the client identifier to AJIT. This avoids both the overhead of setting up a new connection to the database, and the overhead of initializing a new application context.
Note that the client identifier can be anything the application wishes to base access control upon; it need not be an application username.
Another way in which the client identifier can be used for applications whose users are not database users, is to use the client identifier as a type of group or role mechanism. For example, suppose a Marketing application has three types of users: standard partners, silver partners, and gold partners. The application could use the global application context feature to set up three types of contexts (standard, silver, and gold). The application then determines which type of partner a user is, and, passes the client identifier to the database for a session. The client identifier (standard, silver, or gold) here acts like a pointer to the correct application context. There may be multiple sessions that are silver, for example, and yet they all share the same application context.
This feature provides a centralized location to store the user's application context, enabling applications to set up the user's contexts during initialization based upon the user's identity. In particular, it supports Oracle Label Security labels and privileges. This feature makes it much easier for the administrator to manage contexts for large numbers of users and databases.
This section contains these topics:
Application context initialized globally utilizes the Lightweight Directory Access Protocol (LDAP). LDAP is a standard, extensible, and efficient directory access protocol. The LDAP directory stores a list of users to which this application is assigned. Oracle9i can use Oracle Internet Directory as the directory service for authentication and authorization of enterprise users. (Note that enterprise user security requires Oracle Advanced Security.)
The LDAP object orclDBApplicationContext (a subclass of groupOfUniqueNames) has been defined to store the application context values in the directory. The location of the application context object is described in Figure 12-1, which is based upon the Human Resources example.
Note that an internal C function is required to retrieve the orclDBApplicationContext value. A list of application context values is returned to RDBMS.
|
Note: In this example, HR is the namespace, Title and Project are the attributes, and Manager and Promotion are the values. |

The administrator sets up the user's global application context values at the database and the directory.
When a global user connects to the database, the Oracle Advanced Security option performs authentication to verify the identity of the user connecting to the database. Once the identification is completed, the user's global roles are retrieved from LDAP. Then the user's global application context is retrieved from LDAP. Thus, when the user logs on to the database, her global roles and initial application context are already set up.
The initial application context for a user, such as department name, level (title) can be set up and stored in the LDAP directory. The values are retrieved during user login so that the context is set properly. In addition, any information related to the user is retrieved and stored in the application context namespace SYS_USER_DEFAULTS. The following example shows how this is done.
CREATE CONTEXT HR USING hrapps.hr_manage_pkg INITIALIZED GLOBALLY;
An example of the entries added to the LDAP directory follows. These entries create an attribute name Title with attribute value Manager for the application (namespace) HR, and assign usernames user1 and user2.
dn: cn=OracleDBAppContext,cn=myDomain,cn=OracleDBSecurity,cn=Products,cn=OracleC ontext,ou=Americas,o=oracle,c=US changetype: add cn: OracleDBAppContext objectclass: top objectclass: orclContainer dn: cn=HR,cn=OracleDBAppContext,cn=myDomain,cn=OracleDBSecurity,cn=Products,cn=O OracleContext,ou=Americas,o=oracle,c=US changetype: add cn: HR objectclass: top objectclass: orclContainer dn: cn=Title,cn=HR,cn=OracleDBAppContext,cn=myDomain,cn=OracleDBSecurity,cn=Prod ucts,cn=OracleContext,ou=Americas,o=oracle,c=US changetype: add cn: Title objectclass: top objectclass: orclContainer dn: cn=Manager,cn=Title,cn=HR,cn=OracleDBAppContext,cn=myDomain,cn=OracleDBSecur ity,cn=Products,cn=OracleContext,ou=Americas,o=oracle,c=US cn: Manager objectclass: top objectclass: groupofuniquenames objectclass: orclDBApplicationContext uniquemember: CN=user1,OU=Americas,O=Oracle,L=Redwoodshores,ST=CA,C=US uniquemember: CN=user2,OU=Americas,O=Oracle,L=Redwoodshores,ST=CA,C=US
inetOrgPerson object entry exists for the user, the connection will also retrieve all the attributes from inetOrgPerson and assign them to the namespace SYS_LDAP_USER_DEFAULT. The following is an example of an inetOrgPerson entry:
dn: cn=user1,ou=Americas,O=oracle,L=redwoodshores,ST=CA,C=USchangetype: addobjectClass: topobjectClass: personobjectClass: organizationalPersonobjectClass: inetOrgPersoncn: user1sn: OnegivenName: Userinitials: UOtitle: manager, product developmentuid: uonemail: uone@us.oracle.comtelephoneNumber: +1 650 123 4567employeeNumber: 00001employeeType: full time
When user1 connects to a database that belongs to domain myDomain, user1 will have his Title set to Manager. Any information related to user1 will be retrieved from the LDAP directory. The value can be obtained using the syntax
SYS_CONTEXT('namespace','attribute name')
For example:
DECLARE tmpstr1 VARCHAR2(30); tmpstr2 VARCHAR2(30); BEGIN tmpstr1 = SYS_CONTEXT('HR','TITLE); tmpstr2 = SYS_CONTEXT('SYS_LDAP_USER_DEFAULT','telephoneNumber'); DBMS_OUTPUT.PUT_LINE('Title is ' || tmpstr1); DBMS_OUTPUT.PUT_LINE('Telephone Number is ' || tmpstr2); END;
The output of the above example is:
Title is Manager Telephone Number is +1 650 123 4567
Fine-grained access control allows you to build applications that enforce security policies at a low level of granularity. You can use it, for example, to restrict a customer who is accessing an Oracle server to see only his own account, a physician to see only the records of her own patients, or a manager to see only the records of employees who work for him.
When you use fine-grained access control, you create security policy functions attached to the table, view, or synonym on which you have based your application. Then, when a user enters a DML statement (SELECT, INSERT, UPDATE, or DELETE) on that object, Oracle dynamically modifies the user's statement--transparently to the user--so that the statement implements the correct access control.
This section covers:
Fine-grained access control provides the following capabilities:
Attaching security policies to tables, views, or synonyms rather than to applications provides greater security, simplicity, and flexibility.
Attaching a policy to a table, view, or synonym overcomes a potentially serious application security problem. Suppose a user is authorized to use an application, and then, drawing on the privileges associated with that application, wrongfully modifies the database by using an ad hoc query tool, such as SQL*Plus. By attaching security policies to tables, views, or synonyms, fine-grained access control ensures that the same security is in force, no matter how a user accesses the data.
Adding the security policy to the table, view