554 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence are returned. The other important thing to notice in this package is the VPD tagging function called VPD_TAG: CREATE OR REPLACE PACKAGE bi_select.channel_policy AS FUNCTION vpd_whereclause ( schema_name IN VARCHAR2, object_name IN VARCHAR2) RETURN VARCHAR2; FUNCTION vpd_tag ( v_channel_manager IN VARCHAR2) RETURN VARCHAR2; END; / CREATE OR REPLACE PACKAGE body bi_select.channel_policy AS FUNCTION vpd_whereclause ( schema_name IN VARCHAR2, object_name IN VARCHAR2) RETURN VARCHAR2 AS v_whereclause VARCHAR2(2000):=''; v_client_id VARCHAR2(30) :=''; BEGIN SELECT sys_context('USERENV','CLIENT_IDENTIFIER') INTO v_client_id FROM dual; IF v_client_id IS NOT NULL THEN v_whereclause := 'channel_id in (select channel_id from bi_tables.channel_managers where upper(bi_tables.channel_managers.user_name) = upper('''|| v_client_id||'''))'; ELSE v_whereclause := '1=0'; END IF; RETURN v_whereclause; END; FUNCTION vpd_tag ( v_channel_manager IN VARCHAR2) RETURN VARCHAR2 AS v_return VARCHAR2(2000) := NULL; Chapter 14: Securing Oracle BI Content and Data 555 BEGIN FOR r IN (SELECT TO_CHAR(channel_id) channel_id FROM bi_tables.channel_managers WHERE upper(user_name) = upper(v_channel_manager) ORDER BY 1 ) LOOP v_return := v_return || r.channel_id || ';'; END LOOP; IF v_return IS NOT NULL THEN v_return := SUBSTR(v_return,1,LENGTH(v_return)-1); END IF; RETURN v_return; END; END; / The tag on the Oracle BI cache entry will consist of the values of the security sensitive session variables for the user that issued the query. Figure 14-15 shows the definition of the session variable VPD_TAG—notice that Security Sensitive is selected. The code to populate this session variable, in the initialization block GET_VPD_TAG, makes use of the VPD tagging function: select channel_policy.vpd_tag(':USER') from dual FIGURE 14-15 The security session variable VPD_TAG that will be used to tag cache entries 556 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence For the user BICHANNEL1, the VPD_TAG session variable is set to 9, and for users BICHANNEL2 and BICHANNEL3, the value is set to 4. When we test this, we should see that out of these three users, only BICHANNEL2 and BICHANNEL3 can share cache entries. The mechanism for tagging the cache entries is the key to ensuring the Oracle BI cache does not violate VPD policies. If the effect of the VPD policy will yield different results for two different users, then the VPD tag should use different values for these two users. Because the logic that defines the VPD tag is tied so closely to the VPD policy itself, I decided to build this logic directly into my VPD policy PL/SQL package. The BI_SELECT.CHANNEL_POLICY PL/SQL package contains the logic to generate both the VPD predicate and the VPD tag. The function called VPD_ WHERECLAUSE is used by the VPD policy to generate the predicate that will be appended to all queries against the SH.SALES_FACTS table. The function called VPD_TAG generates the value that should be used to tag cache entries. Testing the VPD Example Testing this feature is worthwhile, because it helps you understand how it works. The goal of this test is to show that the BI server uses the cache only when it will not violate the VPD policy. This test requires three users: BICHANNEL1, BICHANNEL 2, and BICHANNEL 3 (see the appendix for more details on these users). If you take a quick look at the BI_SELECT.CHANNEL_MANAGERS table shown in Figure 14-14 and the SH.CHANNELS table, you will see that BICHANNEL1 manages the TeleSales channel, while BICHANNEL 2 and BICHANNEL 3 manage the Internet channel. We will run an Oracle BI Answers request for each user. This will be a very simple report that returns the sales for each channel. Figure 14-16 shows the definition of this report in Oracle Answers. Figure 14-17 shows the results of this query when executed by BICHANNEL1. Figure 14-18 shows the results of this query when executed by BICHANNEL2 or BICHANNEL3. FIGURE 14-16 The request that will be executed by all three users Chapter 14: Securing Oracle BI Content and Data 557 These results are the exact results that we would expect to see with the VPD policy. The user BICHANNEL1 can see only the sales for the TeleSales division. The users BICHANNEL2 and BICHANNEL3 can see only one the sales for the Internet division. This tells us that the database is appropriately applying the VPD policy. It also tells us that BICHANNEL1 is not sharing a cache entry with BICHANNEL2 and BICHANNEL3. Had the BI server used the cache to satisfy the request, we would have seen the same results for all three users. The last thing we need to check is that BICHANNEL2 and BICHANNEL3 are able to share cache entries, because the VPD policy limits both users to the same set of data. Here are the steps required to verify this: 1. Clear all cache entries. 2. Run the query as BICHANNEL1. 3. Check the logs and verify the BI server sends a query to the database (no cache entries are available). 4. Run the query as BICHANNEL2. FIGURE 14-17 The results when executed by BICHANNEL1 FIGURE 14-18 The results when executed by BICHANNEL2 or BICHANNEL3 558 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence 5. Check the logs and verify the BI server sends a query to the database. BICHANNEL2’s VPD_TAG session variable does not match the VPD_TAG attached to BICHANNEL1’s cache entry. 6. Run the query as BICHANNEL3. 7. Check the logs and verify that BICHANNEL3 was able to use the cache entry generated by BICHANNEL2. BICHANNEL3’s VPD_TAG session variable matches the VPD_TAG attached to BICHANNEL2’s cache entry. Now we’ll clear all cache entries using the Manage Cache utility in the Administrator tool. Then, the log level needs to be raised for the three users we will use for our test: BICHANNEL1, BICHANNEL2, and BICHANNEL3. Log levels range from 0 to 7. Productions systems should run with a log level of 0 to avoid unnecessary overhead and should be raised for testing only for troubleshooting. The log level needs to be set to a value of at least 2 to see the physical queries that are issued to the database. If you are using the RPD with internal security, the log level for each user can be adjusted on the user property page in the RPD. If we use any of the RPDs with externalized security, we need to set a session variable called LOGLEVEL equal to a value of 2 or higher for each user, to raise the log level for a user. We can temporarily turn on logging for a user easily by issuing the command set variable LOGLEVEL=2; in the Prefix box on the Advanced tab of an Answers request. You can see this in Figure 14-19. To see the logs generated by each user, you will need to open a browser window and log in as an administrator (BIADMIN in the example RPDs). This allows you to get to the Manage Sessions screen from the Administration window. For each session, you can see the log files that are generated. Here is a snippet of the log file that BICHANNEL1 generated: +++bichannel1:720000:720003: 2008/10/10 16:15:09 Sending query to database named orcl (id: <<268155>>): select T3192.CHANNEL_DESC as c1, sum(T3276.AMOUNT_SOLD) as c2, T3192.CHANNEL_ID as c3 from SH.CHANNELS T3192, SH.SALES T3276 where ( T3192.CHANNEL_ID = T3276.CHANNEL_ID ) group by T3192.CHANNEL_DESC, T3192.CHANNEL_ID order by c1 FIGURE 14-19 Raise the user’s log level by setting the LOGLEVEL variable on the Advanced tab in Answers. Chapter 14: Securing Oracle BI Content and Data 559 Next, here’s BICHANNEL2’s log file entry: +++bichannel2:700000:700003: 2008/10/10 16:17:34 Sending query to database named orcl (id: <<267859>>): select T3192.CHANNEL_DESC as c1, sum(T3276.AMOUNT_SOLD) as c2, T3192.CHANNEL_ID as c3 from SH.CHANNELS T3192, SH.SALES T3276 where ( T3192.CHANNEL_ID = T3276.CHANNEL_ID ) group by T3192.CHANNEL_DESC, T3192.CHANNEL_ID order by c1 Finally, here’s the log file for BICHANNEL3: +++bichannel3:710000:710005: 2008/10/10 16:19:57 Cache Hit on query: Matching Query: SET VARIABLE QUERY_SRC_CD='Report',LOGLEVEL=2; SELECT Channels."Channel Desc" saw_0, "Sales Facts"."Amount Sold" saw_1 FROM SH ORDER BY saw_0 Created by: bichannel2 To summarize, all three of these users ran the same report or logical query. User BICHANNEL2 was not able to use the BI server cache entry created by BICHANNEL1, because the two users’ VPD tags do not match. However, user BICHANNEL3 is able to use the cache generated by BICHANNEL2 because they have the same VPD tags. Deciding When to Use VPD or Oracle BI Row-level Security At first glance, VPD and Oracle BI row-level security may seem a bit redundant. However, you might want to use both of these types of data security for several reasons. Following a basic good security practice, using both VPD and the BI filters, provides defense-in-depth for multiple layers of protection, as shown next: 560 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence Applying security at the database (VPD) puts the security as close to the data as possible. This method’s biggest advantage is that security is enforced no matter how the database is accessed: Oracle BI, SQL*Plus, a web application, or any other access method. NOTE VPD policies are applied to all applications that access the database. Oracle BI security filters are applied only to queries issued via Oracle BI. Applying security at the BI layer provides its own benefits as well. For example, a business model filter might be applied to data that actually comes from multiple physical sources. In this case, the filters need to be defined only once: at the business model layer of the BI metadata. In addition, business model filters in Oracle BI allow VPD-like security to be added to any backend data source that Oracle BI supports (multidimensional data sources, relational database—both Oracle and non-Oracle, Access database, spreadsheets, and XML data files). At this point, you may be wondering which of these two row-level security mechanisms you should implement. As we implied, they are not mutually exclusive. If, however, you find that one mechanism meets all your needs, it is unlikely that you would replicate the work in another layer. So which should you implement? Here are a number of things you might consider: Will the data be accessed by something other than the BI server applications? It is absolutely critical that the data is secure at all times by all access mechanisms. Putting the security as close to the data as possible ensures that the security is not intentionally or inadvertently bypassed. Will the backend database support row-level security? Oracle BI allows for a number of backend databases. Using Oracle BI, you can apply row-level security no matter what the backend data source is (XML, Excel, Access, and so on). How much work will be required to implement these features? I’ve worked with some clients that already have the VPD policies in place and just needed to make sure that Oracle BI could respect those policies. Other clients are adding BI on top of existing systems where it would require a lot of work to add VPD. They tend to find Oracle BI business model filters easier to implement. Who is responsible for the security? If the DBA is responsible for the security, VPD would be the logical choice. If the BI application administrator is responsible for the database, it might be easier to implement security as part of the BI deployment. What are the audit requirements? Applying the security policy in the database using VPD allows all the security to be centralized. This not only makes it easier for auditors to inspect the security policies, but it also makes it easier to ensure that the policies are not bypassed or altered. Does the data need to be protected from the administrators? Oracle BI business model filters do not apply to administrators. If it is important to secure your data from administrators, database security options should be employed. In fact, this is the perfect situation for integrating Oracle BI with Database Vault. ■ ■ ■ ■ ■ ■ Chapter 14: Securing Oracle BI Content and Data 561 In addition to these considerations is one more implementation consideration. Oracle BI business model filters and VPD polices are applied at different levels. VPD policies are applied at the object level. Every query issued by every user will be affected by the policy. If you want to exclude the policy from being applied to a user, that must be designed into the policy itself or you have to make use of the EXEMPT ACCESS POLICY privilege. An Oracle BI business model filter is applied to an object at the group level. Business model filters will affect only members of the group where the filter is defined. Users that are not members of this group are completely unaffected by the business model filters attached to the group. You can, of course, make this group as large or as small as you want. You could design the group so that everyone is a member. In summary, VPD policies affect every user by default, whereas Oracle BI business model filters only affect the member of the group where the filter is defined. In conclusion, Oracle VPD and Oracle BI business model filters are mechanisms used to enforce row-level security. Oracle BI is designed to work with VPD and even has a VPD-aware caching architecture. Oracle BI business model filters provide a quick and easy way to add row- level security to your BI environment, but the are applied only to data accessed through Oracle BI. In addition, they can be used with any supported Oracle BI data source. Oracle VPD has the distinct advantage of being closer to the data. VPD policies will be applied no matter how the data is being accessed. NOTE Oracle BI has been optimized to work with VPD. Oracle BI and Database Vault This section explains how the concepts introduced in Chapters 4 through 7 can be applied to the concepts discussed in this and the previous chapter. Chapter 6 focused on creating a security policy around a Sales Management application. This included transactional, batch, and reporting use cases. In this section, we focus primarily on the reporting use case, as Oracle BI is a reporting tool. However, as Oracle BI can be placed on top of transactional or warehouse data models, the other use cases in Chapter 6 can also be useful for someone attempting to integrate Oracle BI and Database Vault (DBV). Factors and Oracle BI Recall from Chapter 4 that factors are discrete security-related attributes that resolve to a specific value. In Oracle BI, factors can be used in number of ways. They might be used directly as part of the Oracle BI authentication and authorization process or to simplify the definition of Oracle BI session variables. In Chapter 13, we used initialization blocks to authenticate and authorize users. Factor functions are ideal for initialization blocks. Using factor functions greatly simplifies the development of initialization blocks by allowing the Oracle BI administrator to reuse existing security code. This also allows you to put your security policies in a central place (the DBV), making it easier for auditors to verify compliance with security requirements. Finally, the definition of the factor function is protected by DBV. When the code used to retrieve security- related information is stored in an initialization block, any authorized BI server metadata developer can modify that code. Moving the code into a DBV-protected factor means that only authorized realm users will be able to modify the factor definition. 562 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence When using factors to establish Oracle BI session variables, remember that Oracle BI uses shared connection pools to retrieve database information. For example, if we wanted to use the factor User_Department_Name, as defined in Chapter 5, the initialization block query would simply be select DVF.F$USER_DEPARTMENT_NAME FROM DUAL. This factor function uses the database session to return the value of the factor. This will work only if we have properly conveyed the end user’s identity to the database. One way for Oracle BI to convey the end user’s identity would be to use the technique discussed earlier in this chapter to set a client identifier. Another way to convey the end user’s identity would be to use the technique discussed in Chapter 5 to set the CLIENT_IDENTIFIER factor. This technique discussed how to use the concepts of factor assignment and factor validation to set the client identifier in a more trusted manner. The example presented in Chapter 5 demonstrated how the factor could be assigned only from an application server that used a specific certificate as part of the database authentication process. In this case, the application server would be the BI server. Before using the factor User_Department_Name with Oracle BI, we need to make one modification. The code that defined the factor called hr.employee_utility.get_user_department_ name without any parameters. By default, this function uses SYS_CONTEXT('USERENV', 'SESSION_USER') ) as input. But this will not work with the way Oracle BI uses connection pools, so the factor should call the get_user_department_name function passing the client identifier as input. In this case the factor definition would look like this: dbms_macadm.create_factor( factor_name => 'User_Department_Name' , factor_type_name => 'User', description => 'The name of the department the current user works in.', rule_set_name => NULL , get_expr => 'hr.employee_utility.get_user_department_name( sys_context(''USERENV'',''CLIENT_IDENTIFIER''))', validate_expr => null, identify_by => dbms_macutl.g_identify_by_method, labeled_by => dbms_macutl.g_labeled_by_self, eval_options => dbms_macutl.g_eval_on_access, audit_options => dbms_macutl.g_audit_on_get_error, fail_options => dbms_macutl.g_fail_with_message); To set the DEPARTMENT_NAME session variable, we would use an initialization block to issue the query select DVF.F$USER_DEPARTMENT_NAME FROM DUAL via a connection pool. This connection pool would have a logon script that calls dvsys.set_factor(‘Client_Identifier’, ‘:USER’). Actually, to use the procedure dvsys.set_factor as part of a logon script, it would need to be wrapped in a function just as we did with dbms_session.set_identifier earlier in the chapter. The logon script would ensure that the end user’s identity is properly conveyed to the database before attempting to retrieve the department name factor. Once the Oracle BI session variable DEPARTMENT_NAME is set, it could be used as a part of a business model filter to appropriately limit the data the end user can see. Chapter 14: Securing Oracle BI Content and Data 563 Realms and Oracle BI In designing the examples included at www.OraclePressBooks.com, we took care to follow the principles discussed in Chapter 1. In particular, if you examine the setup scripts, you will find objects owner accounts and user access accounts. Let’s quickly review the database accounts used in the examples. For the application data, the object owner accounts used are SH and BI_TABLES, while the user access account is BI_SELECT. Earlier in the chapter we saw how every end user connected via a shared connection pool (BI_ SELECT) to retrieve information from the database. We also examined how to convey the end user’s identity to the database for the purposes of identification and auditing. A similar setup was used for the security-related information used in the examples. The object owner accounts are BI_ SECURITY_TABLES and BI_USAGE_TRACKING and the user access account is BI_SECURITY_ SELECT. The next thing you will notice is that in just the first two setup scripts, it took 25 grant commands to set up the user access accounts properly, even for such a simple example. This is where the concept of DBV realms becomes very useful. In the security setup for these examples, we have effectively described two realms. All the application-related objects, all objects owned by SH and BI_TABLES, could be placed in one realm. All security-related objects, all objects owned by BI_SECURITY_TABLES and BI_USAGE_TRACKING, could be placed in another realm. The user access accounts would be added as realm participants. Chapter 5 gives examples of how to set up these realms and add objects and participants to the realm. Without DBV protections, it is actually quite easy to circumvent our previous BI security setup. All it takes is a database user with the SELECT ANY privilege to bypass all the work we put into designing our architecture. Putting these objects in a realm fixes this problem by immediately controlling access via ANY privileges. In addition, the management of access to objects can be eased by granting the appropriate realm participant SELECT ANY TABLE without worrying about granting too many privileges to the participants. Once DBV is installed and configured, accounts with system ANY privileges can no longer access or manipulate objects protected by the realm. TIP The benefit of placing the objects in realms is that it immediately and transparently protects all the BI data and security-related BI objects from other privileged database users. Recall that more than just tables and views can be added to the realm. This is an important point. Another object to add to the realm would be the VPD policy; this ensures that the security policy protecting the data is also secured. The BI_ACCESS role used in the example could also be added to the realm; this would ensure that this role could be granted only by the accounts or roles authorized as owners of the realm. Auditing The caching capabilities of Oracle BI introduce some interesting security questions, and the same is true with auditing. It might seem like the hardest part of auditing when using Oracle BI would be capturing the end user’s identity from within the database as the user has connected via a . in Oracle BI allow VPD-like security to be added to any backend data source that Oracle BI supports (multidimensional data sources, relational database both Oracle and non -Oracle, Access database, . BICHANNEL2 or BICHANNEL3 558 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence 5. Check the logs and verify the BI server sends a query to the database. BICHANNEL2’s VPD_TAG. entries 556 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence For the user BICHANNEL1, the VPD_TAG session variable is set to 9, and for users BICHANNEL2 and BICHANNEL3,