544 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence block titled GET_PRODUCTS. This initialization block uses row-wise initialization to create and populate a session variable called PRODUCT. Here is the query in that initialization block: select 'PRODUCT' variable_name, product variable_value from bi_tables.product_managers where user_name = ':USER' This query returns the appropriate products for each product manager. The predicate here, user_name = ‘:USER’, ensures that only the correct products are returned. Figures 14-5 and 14-6 show the Utilities dashboard included as part of this example. Figure 14-5 shows the variables when BIPRODUCT1 is logged into Oracle BI, and Figure 14-6 shows the variables when BIPRODUCT2 is logged into Oracle BI. Notice that BIPRODUCT1 has a session variable of PRODUCT = Game Consoles and BIPRODUCT2 has a session variable of PRODUCT = Portable PCs;Desktop PCs. FIGURE 14-4 The PRODUCT_MANAGERS table FIGURE 14-5 The Utilities dashboard when BIPRODUCT1 is logged into Oracle BI Chapter 14: Securing Oracle BI Content and Data 545 Now that the session variable is set up and working, we can define the business model filter. Applying the Business Model Filter Business model filters are set up in the Permissions dialog box for a given group. As you can see in Figures 14-7 and 14-8, several interesting security features are included in the Permissions dialog box. The General tab lists all subject area and column-level security restrictions (column-level security is discussed in the next section). Figure 14-7 shows the Query Limits tab, where you set limits on when databases can be queried, the maximum number of rows, and the maximum amount of time that can be spent on a query. The Populate Privilege refers to a feature used by the marketing feature of Oracle BI. The Execute Direct Database Requests privilege is discussed later in this chapter in the section “Direct Database Requests.” In the Filters tab, shown in Figure 14-8, you can set up business model filters. FIGURE 14-6 The Utilities dashboard when BIPRODUCT2 is logged into Oracle BI FIGURE 14-7 The Query Limits tab of the Product Managers group permissions dialog box 546 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence In this example, a business model filter is applied to the Products and Sales Facts table. Whenever a product manager includes a query against the Products or Sales Facts tables, the filter SH.Products.”Prod Subcategory” = VALUEOF(NQ_SESSION. “PRODUCT”) is added to the query. Notice a few interesting things. First, the filter is making use of the product session variable that we defined earlier. Second, the filter can use any column in the subject area even if the table containing that column is not included in the query. The BI server will automatically join in any necessary tables when it generates the physical query. In this example, the same filter, which uses a column in the Products table, is applied to both the Products and the Sales Facts tables. If the user queries only the Sales Facts table, the BI server will automatically join in the Products table so that the filter can be appropriately applied. Finally, note that the equal sign works here even if the product session variable contains multiple values. The BI server is smart enough to know how to use row-wise initialized variables with equality checks. In working through this example, you may have noticed that the syntax for accessing the session variable when using the web interface is different from the variable when using Administrator tool. To access a session variable while working in the web interface to Oracle BI, you use the syntax @{biServer.variables[‘NQ_SESSION.PRODUCTS’]}. In the Administration tool, you use the syntax VALUEOF(NQ_SESSION.”PRODUCT”). TIP Be careful of the syntax when accessing session variables. The syntax in the web interface is different from the syntax used in the Administration tool. FIGURE 14-8 Business model filters for the Product Managers group Chapter 14: Securing Oracle BI Content and Data 547 Column-level Security Oracle BI supports the ability to apply column-level security. The process of setting up column- level security is very similar to that of setting up subject area security. By default, if a user has access to a subject area, she would have access to all tables and columns in that subject area. If a column should not be seen by a user or group of users, Read access can be revoked. In the Administration tool, column-level security is defined in the Permissions dialog box of the column’s properties. The mechanics of securing access to a column is straightforward and requires nothing more than a few steps. After the column is secured, you’ll need to take a few more steps to ensure a satisfying end user experience. Let’s investigate two use cases to help you understand how this is done: an end user creating a new ad hoc request using a subject area containing secured columns, and an end user attempting to run a report or dashboard that uses a secured column. The example RPD called AOS_INTERNAL_COLUMN_SEC.RPD, which is supplied at www. OraclePressBooks.com, has a secured column in the SH subject area. The “Sales Facts”.“Amount Sold” column is not accessible to the users BICHANNEL1 and BICHANNEL2. If BICHANNEL1 tries to create a new ad hoc query using the SH subject area, this column will not appear in the list of available columns. This use case requires no additional work. For the second use case, assume that an administrator creates a report that uses the column “Sales Facts”.“Amount Sold”. BICHANNEL1 is not allowed to use that column. Using the default setup of Oracle BI, if BICHANNEL tries to run this report, it will error out: “[nQSError: 27005] Unresolved column.” This result is not acceptable and better options are available. These options require some additional steps to set up, as outlined in the following. First, turn on the BI Server parameter PROJECT_INACCESSIBLE_COLUMN_AS_NULL, found under the security section of the NQSConfig.ini file (located in the OraceBI_HOME/server/config directory). By default, this parameter is set to NO. Changing this to YES will stop the error from occurring. Instead, that column will be dropped from the report as if it were never included in the report at all. This is better than the preceding option, but it may still not be what you are looking for. Let’s consider an example report that has three columns: CUSTOMER_NAME, CUSTOMER_ CREDIT_LIMIT, and TOTAL_ORDERED. If the secured column is CUSTOMER_CREDIT_LIMIT, the parameter setting solution might be acceptable. When BICHANNEL1 runs the report, this column will be missing, but CUSTOMER_NAME and TOTAL_ORDERED will still appear on the report and the report is useful. If the secured column was instead CUSTOMER_NAME or TOTAL_ ORDERED, this would probably be a different story, because dropping CUSTOMER_NAME or TOTAL_ORDERED off the report would probably make the report unusable. Oracle BI provides two functions to help deal with this column-level end-user experience problem: choose and IndexCol. With the following two examples, you should still make sure the parameter PROJECT_INACCESSIBLE_COLUMN_AS_NULL is set to YES. The choose Function Oracle BI functions can be applied in two possible locations. A report developer can use a function while developing the report in the web interface, or a metadata developer can use a function in the business model layer of the BI server metadata. The choose function is usable by a report developer only in the web interface. It is not allowed as a business model function. The choose function takes a list of expressions as inputs and returns the first one in the list that the user actually has permission to see. In the example provided on the Web (AOS_ INTERNAL_COLUMN_SEC.RPD) are three “Amount Sold” columns: “Amount Sold” Accessible to everyone except BICHANNEL1 and BICHANNEL2. This column includes all sales. ■ 548 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence “Amount Sold TeleSales” Accessible to everyone except BICHANNEL2. This column is based on a logical column that filters the sales only to sales from the TeleSales channel. “Amount Sold Internet” Accessible to everyone except BICHANNEL1. This column is based on a logical column that filters the sales only to sales from the Internet channel. Let’s assume that we want to create a report that shows the amount sold by product category. We also want this report to work for everyone, including the users BICHANNEL1 and BICHANNEL2. Using just the column “Amount Sold” will not work for BICHANNEL1 and BICHANNEL2, because they do not have access to this column. Instead, we should use the following function: choose("Sales Facts"."Amount Sold","Sales Facts"."Amount Sold TeleSales", "Sales Facts"."Amount Sold Internet") When anyone other than BICHANNEL1 or BICHANNEL2 logs onto the system, they will see “Amount Sold.” When BICHANNEL1 logs on and runs this report, “Amount Sold TeleSales” will be returned. When BICHANNEL2 logs on and runs this report, “Amount Sold Internet” will be returned. This technique handles the problem very nicely, but it requires that both the business model and the report be designed with column security in mind. The IndexCol Function The last tool that Oracle BI provides to deal with this challenge is a function called IndexCol, which is designed to be used in the metadata at the business model layer. This function uses an external function to determine what column should be used. The syntax for the function is IndexCol(external function, column list). The external function should return an integer that represents which column that should be used. A 0 means the first column will be used, a 1 means the second column will be used, and so on. A common way to use this function is to use a session variable for the external function. In this case, an initialization block will run some type of query to determine which column should be used and populate the session variable with the appropriate integer. You should note a couple of interesting things about this function. It is executed as part of the logical request generation, and this means that the logical SQL, including the query log and usage tracking, will contain the IndexCol function. However, cache hits will be determined after the IndexCol function is evaluated. In addition, the IndexCol function is designed to be used inside a hierarchy. Hierarchies are defined within the business model of the BI server metadata. They define the relationships between levels in a dimension. A hierarchy will manifest itself to the end user as a drill path. Because the IndexCol function can be used as part of a hierarchy, the evaluated expression will be drillable just as if the final resulting column were used directly in the report. This makes this type of column-level security very useful for hierarchy security. Let’s work through an example in which product managers should see the entire product hierarchy and all other users should see the product hierarchy only from the product subcategory level down. First, we’ll create an initialization block that returns an integer and populates a session variable called PRODUCT_LEVEL. The following code sets the value to 0 for the users biproduct1 and biproduct2; otherwise it sets a default value of 1: SELECT DECODE(':USER','biproduct1',0,'biproduct2',0,1) FROM dual Next, we create a new logical column that uses the IndexCol function and the PRODUCT_ LEVEL session variable to return the appropriate function. Figure 14-9 shows how this is done. ■ ■ Chapter 14: Securing Oracle BI Content and Data 549 With this function, we have created a new logical column called Top Level that can be used by the report developer. To help you understand how this new logical column works, let’s review the product hierarchy defined in the business model and shown in Figure 14-10. Before any column-level security is implemented, the hierarchy would represent the normal drill path available to end users. The Top Level column does not need to be placed in the hierarchy, but because it evaluates to columns that do live in the hierarchy, it will act like a member of the hierarchy. If biproduct1 runs a report with Top Level in the report, Top Level will evaluate to Prod Category and biproduct1 will be able to drill down the product hierarchy from that point. Figure 14-11 shows a report after biproduct1 has drilled down twice from Top Level. Now, if BIADMIN logs into Oracle BI and runs a report with the Top Level column in it, the results will be different. The Top Level column will evaluate to Prod Subcategory and BIADMIN will be able to drill down from there. Figure 14-12 shows this report for the user BIADMIN. Column-level Security Summary Oracle BI supports column-level security. If you decide to set up column-level security in your metadata, you will need to decide how to handle users who do not have permission to view one or more columns in a report. You have three options: let Oracle BI remove the column from the report automatically, use the choose function in your report FIGURE 14-9 The IndexCol function based on a session variable is an effective technique for implementing column-level security. 550 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence definition, or use the IndexCol function in your metadata. Automatically removing the column from the report may work for some column types, and an example was provided. The choose function works well with column-based security, but using it requires a lot of planning by both the RPD developer and the report developer. The IndexCol function is ideal in times when column- based security is needed for columns that are part of a hierarchy. FIGURE 14-10 The product hierarchy in the SH business model FIGURE 14-11 The logical column Top Level evaluates to Prod Category for the user biproduct1. Chapter 14: Securing Oracle BI Content and Data 551 Integrating Oracle BI with Database Security Policies So far, the focus has been on how to secure data presented through Oracle BI. We have explored security policies that were defined at the BI server level. Now we will examine the steps required integrate Oracle BI with database-level security policies. In particular, we will focus on how Oracle VPD can be used in conjunction with Oracle BI. This discussion of Oracle BI and data security concludes by comparing and contrasting Oracle BI’s row-level security with Oracle Database row-level security. Oracle BI and VPD At a high level, the Oracle VPD feature is similar to business model filters. For example, VPD lets you apply row-level security—in other words, the exact same query will return different results for different users based on their permissions. The rules that define which users will see which rows are captured in a PL/SQL program called a VPD policy that is applied to database tables or views. VPD policies can affect all Data Manipulation Language (DML) statements, and not just queries; however, as this chapter is focused on securing the reporting environment, our discussion is limited to VPD policies applied to select statements. Three steps are required to integrate Oracle BI with a VPD-enabled database: 1. Set up the database session properly. 2. Inform Oracle BI that it will be accessing a VPD-enabled database. 3. Make the BI server cache aware of the VPD policy. Often, VPD policies make use of some attribute about the end user to determine the security enforced. For example, a VPD policy might make use of the end user’s department to limit rows returned in a query. The RPD examples included with this book and found at www.OraclePressBooks .com from the Downloads page are all designed to work with a VPD policy that focuses on sales channels. This policy limits the sales data presented to the user based on the sales channels that the user manages. For this policy to be effective, the database must know who the end user is. FIGURE 14-12 The logical column Top Level evaluates to Prod Subcategory for the user BIADMIN. 552 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence Recall that Oracle BI uses shared connection pools to connect to the database. So to make Oracle BI work with our example VPD policy, we need to convey the end user’s identity to the database. (The mechanics of conveying this information to the database were covered earlier in the chapter.) Next, we must inform the BI server that it is connecting to a VPD-enabled database in the database Properties dialog box in the Administrator tool. As shown in Figure 14-13, you need to mark the database as a Virtual Private Database. This informs the BI server that database security policies may affect the rows returned by a query. Knowing this, the BI server will take additional steps in deciding whether cache entries can be used to satisfy queries. The details of how the BI server cache works with VPD are covered next. Oracle BI Cache and VPD One very interesting feature of the BI server is its sharable cache feature, which allows cache entries to be shared by multiple BI users. This can drastically improve performance, even in high-user scenarios. This might leave you a bit concerned about security. Note that all BI Server security features work natively with the shared cache. In particular, business model filters work with the BI server cache, because business model filters are added to the query before checking to see whether the query can be satisfied by the cache. FIGURE 14-13 Identifying a database as a VPD in the BI server metadata Chapter 14: Securing Oracle BI Content and Data 553 The next big question that probably comes to mind is this: Does the BI cache work with database security features (such as Oracle VPD)? The answer is yes, which is quite amazing considering that the decision to use cache is made before any query is sent to the database where the VPD policy is applied. The key to getting the BI server’s sharable cache to work with Oracle VPD is to tag the cache entries. These tags are basically labels on the cache entries that let the BI server know who should be allowed to share the cache. Let’s look at another example provided on the Web. While examining the example, we will also run through a basic test to verify that the cache is working with the VPD policy. This example includes a simple VPD policy, and all of the example RPDs provided on the Web are designed to work with this VPD policy. We’ll put a VPD policy in place that restricts the rows returned from the SH.SALES table. The rows returned will be restricted so that the end user can see the rows for only the channels that they manage. Figure 14-14 shows the CHANNEL_MANAGERS table that holds information necessary for the VPD policy. Following the three steps listed earlier for integrating Oracle BI with a VPD-enabled database, let’s first make sure that the database session is properly set up and that the user’s identity is conveyed to the database. To do this, we execute the statement select bi_select.set_identifier(‘: USER’) from dual in a connection script for the data access connection pool. The details of how to do this were covered in the section “Setting Client Identifiers.” Second, we mark the database as a VPD database in the BI server metadata. As shown in Figure 14-13, this is done on the Properties page for the ORCL database in the RPD. The Virtual Private Database checkbox must be selected when the underlying database uses VPD policies. This instructs the BI server to start tagging all BI server cache entries. Third, we must make the BI server aware of the VPD policy and instruct the BI server on how exactly it will tag the cache entries. We do this by populating a security-sensitive session variable with information from the VPD policy. The code for the VPD policy used in the examples provided at www.OraclePressBooks.com is listed next. This is a simple policy and is not intended to represent any best practices with respect to VPD policy development. This policy simply applies a filter to the SH.SALES table so that only rows for the channels that the end user manages FIGURE 14-14 The CHANNEL_MANAGERS table used in the VPD policy . security concludes by comparing and contrasting Oracle BI’s row-level security with Oracle Database row-level security. Oracle BI and VPD At a high level, the Oracle VPD feature is similar to. integrate Oracle BI with database- level security policies. In particular, we will focus on how Oracle VPD can be used in conjunction with Oracle BI. This discussion of Oracle BI and data security. biproduct1. Chapter 14: Securing Oracle BI Content and Data 551 Integrating Oracle BI with Database Security Policies So far, the focus has been on how to secure data presented through Oracle BI. We have explored