Sunday, August 12, 2007

Virtual Private Database (VPD) with Oracle Apps

Virtual Private Database (VPD) is an Oracle database security technology, enabling row level access control.
With VPD we are able to control users access to data related to them only and preventing from them to access data they are not authorized to see.
For additional information about VPD take a look at Virtual Private Database in Oracle8i and Oracle9i.

VPD can be used with Oracle Applications 11i, and I'm going to show a very simple example.
So let's assume, for example purpose only, that we would like to prevent some users to view requests that finished with status "ERROR".

The steps to implement VPD are:
1) Create a profile to control which users can see error requests
2) Set profile value to 'N' at site level.
2) Create new context
3) Create context package
4) Create policy package
5) Add policy to concurrent request table

Create profile
To control which users will be restricted and which are not, create a new profile, name - XX_HIDE_ERROR_CONCURRENTS.
Set value at site level to 'N' and for specific user to 'Y':

declare
status boolean;
begin
status := fnd_profile.SAVE(X_NAME => 'XX_HIDE_ERROR_CONCURRENTS'
,X_VALUE => 'N'
,X_LEVEL_NAME => 'SITE');
status := fnd_profile.SAVE(X_NAME => 'XX_HIDE_ERROR_CONCURRENTS'
,X_VALUE => 'Y'
,X_LEVEL_NAME => 'USER'
,X_LEVEL_VALUE => '10083');
end;
/
commit;

Create new context:
CREATE CONTEXT XX_APPS_CONTEXT USING APPS.XX_CONTEXT_PKG;

Create context package:
Create the package used by the new context.
This package will set the context for users according to the user level profile value.

CREATE OR REPLACE PACKAGE XX_CONTEXT_PKG AS
PROCEDURE Set_Context;
END;
/
CREATE OR REPLACE PACKAGE BODY XX_CONTEXT_PKG IS
PROCEDURE Set_Context IS
BEGIN
DBMS_SESSION.Set_Context('XX_APPS_CONTEXT', 'HIDE_ERROR_CONCURRENTS', fnd_profile.VALUE('XX_HIDE_ERROR_CONCURRENTS'));
END Set_Context;
END;
/

Create policy package
Now, we need to create a policy package.
In this package we determine the policy for accessing data, according to the user context we determine how to access the table.

CREATE OR REPLACE PACKAGE XX_POLICY_PACKAGE AS
FUNCTION Select_Concurrent_Requests (Owner VARCHAR2, Objname VARCHAR2)
RETURN VARCHAR2;
END;
/
CREATE OR REPLACE PACKAGE BODY XX_POLICY_PACKAGE IS
FUNCTION Select_Concurrent_Requests (Owner VARCHAR2, Objname VARCHAR2) RETURN VARCHAR2 IS
predicate VARCHAR2(500);
BEGIN
predicate := null;
if (sys_context('XX_APPS_CONTEXT','HIDE_ERROR_CONCURRENTS') = 'Y') then
predicate := 'STATUS_CODE != ''E''';
end if;
RETURN predicate;
END Select_Concurrent_Requests;
END;
/

Add policy to concurrent request table
Applying the policy on the relevant table.

begin
dbms_rls.add_policy('APPS'
,'FND_CONCURRENT_REQUESTS'
,'XX_SELECT_CONC_REQ_POLICY'
,'APPS'
,'XX_POLICY_PACKAGE.Select_Concurrent_Requests'
,'SELECT');
end;
/

From now on, each access to this table will involve context value check and the data is secured.

Let's check if it's work...
Set the current session to my APPS user and execute the Set_Context procedure.

begin fnd_global.apps_initialize(10083, 0, 0); end;
/
begin XX_context_pkg.Set_Context; end;
/

Query all requests that finished with error status should return 0 rows:
select count(*) from fnd_concurrent_requests where status_code='E';
COUNT(*)
----------
0

If we change the session owner:
begin fnd_global.apps_initialize(10084, 0, 0); end;
/
begin XX_context_pkg.Set_Context; end;
/


And execute the same query as before:
select count(*) from fnd_concurrent_requests where status_code='E';
COUNT(*)
----------
157

To drop the policy from the table issue this command:
begin
dbms_rls.drop_policy('APPS'
,'FND_CONCURRENT_REQUESTS'
,'XX_SELECT_CONC_REQ_POLICY');
end;
/


VPD & Oracle Apps
To set the context for each APPS user connect to the system, we can insert into CUSTOM.pll this line only:

begin XX_context_pkg.Set_Context; end;

For Each user connecting to Oracle Apps Forms, the context will be set and security will be on.

This is on VPD & Oracle Apps in a nutshell, The solution is very depents on specific requirements of security but this is a good starting point.

For any questions, impressions or additional information you are welcome to leave a comment.

Aviad

Thursday, August 2, 2007

After ATG RUP 5 Concurrent Managers Fail to Start

Last week I have installed the ATG RUP 5 on my TEST environment.
Everything goes smooth, all additional patche applied successfully, the application startup succesfully, great....

Today, I decide to make some order in this TEST environment and I run FND_CONC_CLONE.setup_clean to clean FND_NODES and all tables that refilled by autoconfig.
Afterwards, autoconfig on DB tier and APPS tier.
I checked the FND_NODES table and it looks like it populated successfully (without the old nodes from source environment...)
I run the adstrtall script to startup apps tier and the Concurrent Managers didn't startup!

The error mesasge I got was:
Could not initialize the Service Manager FNDSM_[SERVER_NAME]_[ENV_NAME]. Verify that [SERVER_NAME] has been registered for concurrent processing. Routine AFPEIM encountered an error while starting concurrent manager....

The cause of this problem is the change of FNDSM trigger in ATG RUP 5.

====================================================
The new FNDSM trigger code is:

CREATE OR REPLACE TRIGGER fndsm
AFTER INSERT ON FND_NODES FOR EACH ROW
BEGIN
if ( :new.NODE_NAME <> 'AUTHENTICATION' ) then
if ( (:new.SUPPORT_CP='Y') or (:new.SUPPORT_FORMS='Y') or (:new.SUPPORT_WEB='Y') ) then
fnd_cp_fndsm.register_fndsm_fcq(:new.NODE_NAME);
end if;
if (:new.SUPPORT_CP = 'Y') then
fnd_cp_fndsm.register_fndim_fcq(:new.NODE_NAME);
end if;
end if;
END;
====================================================

When we run autoconfig on db tier, new row inserted into FND_NODES but FNDSM and FNDIM are not created since db tier not supported CP/FORMS/WEB.
When we run autoconfig on apps tier, this columns are updated to 'Y' but FNDSM trigger is not run because it is fired for insert and not for update.

The Solution is :
1) Recreate the FNDSM trigger same as before but add "AFTER INSERT OR UPDATE ON FND_NODES".
2) Run: exec FND_CONC_CLONE.setup_clean; (with apps)
3) Run autoconfig on db tier and apps tier (in this order)
4) Startup apps tier.

There is no patch at this time to fix this probem, but when ATG RUP 6 will be available it will contain a fix to FNDSM trigger.
Full details in Metalink note 434613.1.

Cheers,
Aviad