« October 2007 | Main | December 2007 »

November 2007 Archives

November 3, 2007

JHeadstart at Oracle Open World

Next week, I will be presenting JHeadstart at Oracle Open World, under the title Oracle JHeadstart: Unprecedented Productivity in Developing Ajax-Enabled Oracle ADF Applications.

With thousands of sessions being scheduled, I decided to go for a teaser abstract:

In maybe the coolest demo of this conference, the speaker uses Oracle
JHeadstart to build a complete enterprise-class application from
scratch in one hour. Features include trees, shuttles, lists of values,
advanced search, tabbed regions, wizards, conditionally dependent
items, deep linking, flex fields, role-based security, dynamic menus,
and more. This presentation is a MUST-SEE for developers with a
Forms/4GL background who are considering moving to J2EE.


So, expectations are set I would say :-). And the best part is not even in the abstract. At the end of the session, I will use an alfa release of JHeadstart R11 to migrate the application in 1 minute to ADF 11, leveraging new features like page templates, tasks flows, and all the new ultra-rich user interface components.

Seeing is believing, if you are coming to OOW, the first session to attend on thursday november 15 (8:30 AM - 9:30) is in Moscone South 308!

November 5, 2007

Row Level Security using VPD and ADF

Suppose you have an ADF web application, and you want multiple users to look at the same database table, but to make certain rows invisible for some users. Also, you might want the possibility to have some of the visible rows (but not all) be read-only, depending on the user.

In this blog post, I will explain how we used VPD with JHeadstart and ADF Business Components in my latest project to get such row level security in our web application.

Key Ring Image:    Contents
What is VPD?
The Application User Problem
The Global Application Context Feature
Only Authorized IP Addresses
The Set Context Procedure
Setting the Context from ADF BC
Making Rows Invisible
Making Rows Read Only

What is VPD?

VPD or Virtual Private Database is a feature of the Enterprise Edition of the Oracle Database. It is also known as Fine-Grained Access Control (FGAC), and some call it Row Level Security (RLS). The database package used for VPD is called DBMS_RLS.

The main functionality of VPD is to automatically add extra where clauses to SQL statements. Depending on how you defined your VPD policies, it can be applied to select, update, insert, and/or delete statements of specific tables.

Quote from Lonneke Dikman's article Implementing Row-Level Security in (TopLink) Java Applications:

The database dynamically alters the query [or DML statements] based on the security policy
and session context. [...] Security policies can be created using stored procedures. Such
policies restrict access by using the content of application data
stored in Oracle Database or context variables, such as user name or IP
address. 




Oracle Label Security
(OLS), an Enterprise Edition option, is an implementation of VPD. Using
OLS, administrators can create policies without writing PL/SQL. Access
to data is mediated based on four factors: Label of the row, Label of the user session, Policy privileges of the session,Policy enforcement options for the table.


To make the VPD policies user / role specific, VPD must know which end user is currently accessing the database. This might seem trivial, but it isn't if you want to use connection pools in the application server.

The Application User Problem

As also described in Fine-Grained Auditing for Real-World Problems, Part 2, by Arup Nanda, in web-based applications, the application server usually connects to the database using a fixed user -- for example, APPUSER. The users of the application are authenticated by the application. Therefore VPD cannot rely on the current database user for its policies, we need to have some mechanism to pass the application user name to VPD.

To make VPD aware of the current end user of an ADF web application when all database connections use the same application user, you can use the Global Application Context feature of the Oracle database, as described in the Oracle whitepaper Leveraging Oracle Database Security with J2EE Container Managed Persistence.
   
If you want to use Oracle Label Security (OLS) and you can use Oracle Internet Directory to identify the users, you might be
interested in the article How
to integrate Oracle Label Security with Oracle Internet
Directory
, which describes how to take the users and the OLS policies
from OID. In other cases, you have more flexibility if you use generic VPD in the database with the Global Application Context feature.

The Global Application Context Feature

To apply this technique you define a global context object in the database, which is like a namespace that has key/value pairs. The only way to set a context is through the PL/SQL package that is bound to that context, for example MY_VPD_CONTEXT_PCK. This method is also explained in the abovementioned article by Arup Nanda and in Pete Finnigan's article Oracle Row Level Security: Part 1.

Only Authorized IP Addresses

To ensure that the end user name is only set in the database context when that user has successfully logged in to the web application, you can add security checks to procedure that sets the context. A simple but effective check is to verify that the call comes from an authorized IP-address like the application server. It relies on the fact that by other means you will have made sure that no unauthorized persons can execute database calls from the application server. This security check is also described in the abovementioned article by Pete Finnigan.

Here is the example code to perform such an IP address check: the function IS_AUTHORIZED_IP_ADDRESS in package MY_VPD_CONTEXT_PCK returns true if the current IP address occurs in a table of authorized IP addresses.

Is Authorised IP Address Code Image:

You can use this function just before setting the context. In addition you could create an AFTER DATABASE LOGON  trigger in which you use the same function to ensure that only authorized IP addresses can log on as the APPUSER.

In the interests of security the MY_VPD_CONTEXT_PCK package, and the MY_AUTHORIZED_IP_ADDRESSES table should not be owned by the APPUSER schema. Instead you can create an APPOWNER schema to which you cannot connect, which owns all application database objects, and only grants privileges that are needed by the web application to the APPUSER schema, for example grant execute on MY_VPD_CONTEXT_PCK. The APPUSER should certainly not be able to modify the MY_AUTHORIZED_IP_ADDRESSES table.

The Set Context Procedure

Now, we can add a procedure SET_CONTEXT to the package MY_VPD_CONTEXT_PCK, that first checks the IP address and then puts the user name in the context, so that they are available for use in VPD policies.

Set VPD Context Code Image:

Note 1 This procedure also sets the Client Identifier. This is a kind of session attribute that is used in Fine Grained Auditing, to audit who has done what. Of course we want to know the end user name in the auditing trails, and not the APPUSER schema name.

Note 2 The SET_CONTEXT procedure uses a global package variable g_database_user that is initialised with the value of the current database user: in our example that would be 'APPUSER'. This value is used to identify the key/value pairs in the context object.

Note 3 In this example one key/value pair are placed in the context: username. Of course you could also pass other parameters to the procedure and store them also as key/value pairs. You could also maintain a cache for frequently used information in the VPD policies, depending on the passed parameters.

Setting the Context from ADF BC

To ensure that the ADF web application sets the context correctly, the context must be set each time a different end user uses a database connection. When you use a pool of database connections, you can never be sure that the next request in a session will use the same database connection as the previous request. In ADF Business Components, the prepareSession() method gets invoked by the application module when it is used for the first time by a new user session (see the ADF Developer's Guide for Forms/4GL Developers: 8.6.3 How to Override prepareSession() to Set Up an Application Module for a New User Session). So that's the ideal method to override in your custom application module class to set the VPD context.

If you let the application server manage your users in the J2EE container, you can implement prepareSession() like this (see also Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 by Lucas Jellema):

Prepare Session Code Image:

Note that in this example we assume that SET_CONTEXT has only one parameter: the username.

If you manage the application users in the ADF application itself, then you of course derive the username in some other way.

In my latest project we found out that setting the VPD context just in prepareSession() was not enough. We had implemented a custom authentication in a servlet filter (using the AuthenticationFilter class supplied in the JHeadstart Runtime library). If the AuthenticationFilter determines that the user has logged in and is not in the process of logging out, it loops over all active data controls and if they are of type JhsApplicationModule it calls setUser() on each application module. If you use JHeadstart you have this JHeadstart superclass in all your Application Modules. To make sure that each active Application Module sets the correct VPD context, even in case of web time outs or deep links, we have overridden the JHeadstart setUser() method and added a call to setVPDcontext() (see the above code example).

Making Rows Invisible

After doing all these preparations, to get Row Level Read Security all you need to do is add select policies on your tables. For instructions how to apply such policies, see the Oracle By Example tutorial Restricting Data Access Using Virtual Private Database. Only instead of calling sys_context('userenv','session_user'), you need to call a function in MY_VPD_CONTEXT_PCK that returns sys_context(g_database_user, 'USERNAME'). Depending on the policy, this will ensure that user A might see different rows than user B when the web application performs a certain database query.

If certain role information is needed often during the execution of the VPD policies, it is advisable to cache as much as you can, because VPD can have a serious impact on performance. Of course you must test carefully that the cache always contains the correct information.

Making Rows Read Only

The next step is to add Row Level Update Security to the application. This is more tricky, because we not only want to prevent certain users from updating certain rows (by showing an error message if they try), we also want to make the rows read-only in the screens (so that they won't even be able to try it). So we want to be able to use some boolean JSF expression to apply to the readOnly property of the JSF / ADF Faces components in our user interface. Furthermore, this expression must be row specific; for each row there could be a different return value.

We implemented this row-level boolean JSF expression using a special IsUpdateable attribute in the ADF BC View Objects. You could make this a transient attribute and code the logic in the getIsUpdateable() method of the ViewRowImpl class, but that get method would be executed each time the attribute is used in an expression, each time the page is displayed or refreshed. We implemented it as a calculated attribute instead, which means the calculation is only executed when the View Object's select-statement is executed in the database. This normally happens only once per user session, unless an explicit "Execute Query" is programmed for the View Object. For more information how calculated attribute values are cached, see the ADF Developer's Guide for Forms/4GL Developers, section 7.7 Understanding How View Objects and Entity Objects Cooperate at Runtime.

The calculated attribute is implemented by calling a database function specific for the table. For example: if we have an Orders table, and we want some Orders to be read-only to certain users, we would add a calculated attribute IsUpdateable to the Orders View Object. In the select-clause we would call a database function MY_UPDATEABLE_PCK.IS_ORDER_UPDATEABLE(p_ord_id number). We pass in the primary key of the row (the order id), and return a string 'TRUE' or 'FALSE'.

Then in the JSF pages, you can add the following expression to the readOnly property of each relevant UI component: readOnly="#{!bindings.IsUpdateable!='FALSE'}" or, in case of a table layout, readOnly="#{!row.IsUpdateable!='FALSE'}". Now you might argue, why this triple denial? Why not simply use something like #{bindings.IsReadOnly=='TRUE'}? Well, there are two reasons:
  1. When generating these pages using JHeadstart, the appropriate place to put this expression is the Update Allowed EL Expression property. To allow for easy-to-read expressions in this property, we prefer to write bindings.IsUpdateable instead of bindings.IsReadOnly. A side effect of using JHeadstart's Insert/Update/Delete allowed expressions is that the New and Save buttons will also be made invisible when they do not apply.
  2. When we used bindings.IsUpdateable=='TRUE', we found out that just after inserting a new row, that row would become read-only, even though it was supposed to be updateable. That's because calculated attributes are only refreshed when re-querying the database. So to make sure that in case the value is unknown (like it is just after insert), the row will be updateable, we use !='FALSE' instead of =='TRUE'.
So, in JHeadstart's Update Allowed EL Expression of a form layout Group we put #{bindings.OrdersIsUpdateable!='FALSE'}. And for an updateable table layout Group it becomes #{row.IsUpdateable!='FALSE'}. In the latter case you can create the effect that in the updateable table some rows are read-only and others can be updated.

November 12, 2007

Speeding Up JDeveloper 10.1.3

In this post I have collected various hints and tips to improve the speed of JDeveloper 10.1.3.x, especially when using multiple faces-config.xml files in JSF (like JHeadstart does).

Some great tips about improving the JDeveloper performance can be found in Shay Shmeltzer's blog post Is your JDeveloper Slow? - It shouldn't be!.

  • Shay's tip #1 is get a better machine. My recommendation is: at least 2 GB internal memory.
  • Shay's tip #4 mentions Gerard Davison's KeepResident. It's worth noting that this JDeveloper extension (for Windows only) can be installed in JDeveloper using Help - Check For Updates - Partners and Open Source Extensions Update Center.
  • Shay's tip #6 mentions that you can disable JDeveloper extensions you don't need. Brian Duff's post Seriously customizing JDeveloper he explains how you can even disable extensions that are not visible in the JDeveloper preferences, but are visible in Help - About.
  • In the comments of Shay's post, Jon Wetherbee reports: Another way to avoid delays when switching back to JDev from another
    app is to turn off the automatic file scan that is enabled by default. To do this, go to: Tools | Preferences | Environment and de-select: 'Automatically Reload Externally Modified Files' and/or: 'Verify Project Contents Automatically on Restart'.
  • To add a tip of my own: configure the JDeveloper Preferences to open files in the Source editor
    by default (Tools | Preferences | File Types, tab Default Editors). The benefit is that you save the time of opening the Design editor if you
    are not going to need it for that particular file. Not only for the
    jspx files, but also for the faces-config files. If a faces-config file
    does not contain any navigation rules but only managed beans, the visual design is not useful anyway.
To check if your efforts were successful in minimizing the memory usage of JDeveloper, you can turn on the memory monitor in JDeveloper, as described in Brian Duff's post "Useful power preferences for JDeveloper and SQL Developer". Unfortunately this post is not online anymore, but the instructions are: find the ide.properties file in your JDeveloper user directory (system10.1.3.xxx), in that file find the MemoryMonitor property, and change false to true. I often found that when the memory monitor displays a high value, restarting JDeveloper helps... The widget is displayed in the lower right corner of JDeveloper, and looks like this:
JDeveloper Memory Monitor widget:

Speeding up JDeveloper when using multiple JSF faces-config files

In his blog post Using multiple faces-config.xml files in JSF, Chris Muir explains how you can split up a large faces-config.xml file into multiple smaller files, that together act as a large faces-config file. This technique is used extensively by JHeadstart: for each group (data collection) in your application definition you get a separate faces-config file with the managed beans for that group. The original faces-config.xml is only used for navigation cases and some application level JSF settings. This has big advantages like keeping each configuration file small, allowing easier Version Control, etc.

However, it also has a disadvantage: it considerably slows down the time needed for opening the ViewController project (and if that project is opened by default, the start-up time of JDeveloper). This has been logged as JDeveloper bug 5706124 (see MetaLink for details about the bug, and see this JHeadstart forum thread for a discussion about it).

Luckily, there is a workaround:
  1. Temporarily remove the javax.faces.CONFIG_FILES parameter from your web.xml file (that is where all the faces-config file names are listed, see section 11.2.3 of the ADF Developer's Guide),
  2. Start up JDeveloper and open your ViewController project,
  3. Put back the CONFIG_FILES parameter.
After that JDeveloper runs just as fast as with only one faces-config file.

While this is good news, it is a nuisance to have to change web.xml every time you start JDeveloper (and if you forget you have this extremely slow startup), and to change it back afterwards (otherwise your application won't run correctly). So I was very happy when my colleague Marcel came up with a way to automate this:
  1. Create a batch script that backs up web.xml, replaces it by a dummy web.xml, starts JDeveloper, and after the ViewController project is opened puts the original web.xml back. On Windows, such a script could look like this (I'm sure that on Linux something similar is possible):
    @echo off
    rem ### Backup web.xml ###
    copy /y viewcontroller\webcontent\WEB-INF\web.xml backup_web.xml
    copy /y dummy_web.xml viewcontroller\webcontent\WEB-INF\web.xml
    rem ### Start JDeveloper ###
    if not defined JDEV_HOME set JDEV_HOME=C:\jdev1013
    start /min /d%JDEV_HOME% %JDEV_HOME%\jdev\bin\jdev.exe
    rem ### Restore web.xml ###
    @echo on
    pause Continue when JDeveloper has opened the ViewController project
    copy /y backup_web.xml viewcontroller\webcontent\WEB-INF\web.xml
    del backup_web.xml
  2. If necessary, change the directory paths in the script to reflect your situation.
  3. Put this script in the root folder of your project, together with a file dummy_web.xml in which the parameter javax.faces.CONFIG_FILES is removed.
  4. Make sure that the shortcut to start JDeveloper points to this batch file instead of to the JDeveloper executable.
Then, when you start JDeveloper, you wil see this:
JDeveloper Startup Batch Window:
Keep the DOS box open until your ViewController project is opened, then go back to the DOS box and press Enter to get the original web.xml back.

That solved my JDeveloper speed problems!

November 26, 2007

ADF BC Diagnostics

One of the old JHeadstart blog posts (of the orablogs site) that is still valid, is the one about ADF BC Diagnostics. It mentions jbo.debugoutput, jbo.logging.show.function, and jbo.logging.show.timing. It also explains how to interpret the timing.

See also the ADF Developer's Guide for Forms/4GL Developers, section 5.5.3.2 Enabling ADF Business Components Debug Diagnostics.

About November 2007

This page contains all entries posted to JHeadstart Blog in November 2007. They are listed from oldest to newest.

October 2007 is the previous archive.

December 2007 is the next archive.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type and Oracle