Thursday, November 3, 2011

ADF Security Basics

ADF security is a pretty deep topic especially when you put it in perspective of an enterprise deployment and how the security infrastructure works together with the application server to provide for the functionality. Also, there are a number of great resources out there that give a good understanding about how to configure and secure an ADF application. My first go-to resources on the web would be :

Oracle ADF Documentation : Section 35
Chris Muir's Blog Post

Having said that, this is a quick look at the various aspects included in ADF Security  and a rundown of whats possible with ADF security and how to implement some fairly common use cases.  The example is based on the HR schema and can be downloaded from here.

In its simplest form, ADF security is declarative and protects pageDef files( for pages in the Unbounded taskflow) and whole BTFs (Bounded Taskflows), it can also be applied to EOs and EO attributes, which I personally consider especially powerful when combined with Oracle Database's VPD feature ( maybe that's a good topic for a blog post ! ).

ADF security is based on OPSS which in turn is based on JAAS. In this model, we create "application roles" and grant permissions to application roles to do certain operations within the application and hence the name. So the ability to do a set of operations is collected and called a role. Now these roles are granted to specific users, which enable those users to do all the actions defined by those roles assigned to them. In a real production environment however, the users are not defined in the context of a single application, instead they would be defined for the whole enterprise and granted access to various applications, all using the same user name (a single sign-on or SSO). So these identities (or users) would be defined in an identity store like LDAP and WLS can work with such systems. In WLS we can create "enterprise roles" which is very similar to application roles, but are defined at the container (app server) level, and so all applications can use them. Therefore, in a production setup, we also have to map application roles to enterprise roles (for each application) and then associate users to the enterprise roles. This makes it possible for developers to develop applications without worrying about enterprise roles or application roles used by other teams and products.

By default when we enable ADF security , the bounded taskflows and the pagedefs for the pages in the unbounded taskflows are secured. The UBTF is not security aware and cannot be secured as a whole like the BTFs. Entity objects and EO attributes are not secured by default, and requires a grant to be given explicitly.

Tip :  to secure a page that does not use the ADF bindings, we can just create an empty pageDef file by right-clicking the page and choosing "Go to PageDef" . This empty pageDef can then be used to secure the page.

EO (and therefore editable VOs) can also be secured on the basis of application roles. Security is applied on two levels for an EO. On the EO as a whole or on a specific property of the EO. For the whole EO, security permissions exist to restrict read,update and delete on the EO. For EO attributes the permission exists to secure the update operation on any field. Column-wise security can be done on the View layer by toggling the visibility of a table column based on a security EL.

More Details & Example Application

The example application tries to demonstrate various use cases and how to secure various parts and pages in an application.The example is built on the standard HR schema and has two bounded task flows apart from the default unbounded task flow. The example has a landing page, and a taskflow to maintain (Search & Edit) Employees and another taskflow to maintain Departments.


For the example, we shall define the following Application roles in our application :

  • EmployeeAccess - can view MaintainEmployees taskflow
  • DepartmentAccess - can view MainatinDepartments taskflow
  • EmpManager - can edit employee details (except salary)
  • DeptManager - can edit department details
  • SalaryManager - can edit salary for employees
 For the purpose of demonstrating various cases, the task flow is structured as below :


The Landing Page
 The landing page, Welcome.jspx,  is accessible for everyone, but also contains an embedded taskflow that is displayed only to authenticated users who have access to view it. There are links on the welcome page that take the user to other pages and require the user to authenticate before the page is displayed to them. The other pages to search for and edit employees and departments, require the user to have various access levels to perform various actions.Welcome.jspx is a publicly accessible page. It is made public by granting 'view' access on this page, to the 'anonymous-role' built in role. To do this, open your jazn-data.xml and follow the steps below :

The jazn-data.xml editor allows you to associate roles to pages/taskflows

The same dialog is used to set permissions for taskflows (change dropdown marked "1" from webpage to Taskflow). The roles defined will be shown in area marked "3".

In the UI pages we can use the security EL to show hide fields or to make then editable and non editable. If you open the expression builder you will see the securityContext object in the bindings object with a number of very useful methods in it.
Notice the expression to check if the user has permission to view a taskflow, and also the various methods exposed by the securityContext object(click to enlarge)


On the welcome page the following EL is used to render the bounded taskflow as a region


This EL basically checks if the logged in user has access to see the taslflow. The taskflow is referenced by giving the path to the taskflow xml file (relative to the WEB-INF directory) followed by the taskflow name.


At this point its worthwhile to note that permissions are usually hierarchical in nature. The role that can edit the salary for an employee would surely have the permissions to edit and view employees. So in our case the permissions would be like this :
Hierarchical Permissions


The Maintain Departments Page
The MainatainDepartments page and taskflow are secured and is available to authenticated users who have the DepartmentAccess permission or above (see the permission hierarchy above ). With the DepartmentAccess permission the users can search departments and view details, but cannot edit anything, because we will ensure that components are editable only based on the permissions granted to the logged-in user. To edit a department, the user needs the DeptManager  permission. This taskflow is also calledby the edit employee taskflow where an employee who has the permission to edit departments can directly edit a department.
-
The Maintain Departments BTF supports parameters to directly show the edit page for a given department.
The Maintain Employees page
The Maintain Employees page and taskflow are also secured and accessible to people with appropriate permissions. Just like Departments, the user needs an EmployeeAccess  permission to view , and an EmpManager permission to edit details. But in this case, we implement EO level security, by requiring the some users to also have a SalaryManager permission to edit a user's salary. The  permission hierarchy screenshot above should make better sense now. SalaryManager gets to everything, the next lower permission, EmpManager gets to edit everything but the salary, and the lowest permission EmpAccess allows only readonly access The taskflow diagram is below :

The Mainatain Employees BTF is simple and has a taskflow call to directly edit Departments.
The EO level security for the salary is set by selecting the EO attribute to enable security on it.
Enabling security on EO attributes.
Once security is enabled, you need to associate roles to it, or no one will be able to edit this attribute.
This is a little tricky just because the JDeveloper menu is very well hidden !
To associate the roles do this :
Select the EO in the navigator window

Right click the EO attribute in the structure window to get the "Edit Authorization" Menu
This opens up the following dialog :

In this dialog, the application roles are displayed and you can grant the permission to the roles you select.

Showing/Hiding UI elements based on permissions
 Since we mostly use EL to check for permissions and decide whether or not to display some attribute, or set the readOnly property, having this hierarchical form is very beneficial as you see below. The code below is for the first column in the result table on the employee search. This column will render a link which can be clicked to view the employee details and edit them for an 'EmpManager' role, but will render as read only text for people with 'EmployeeAccess'. Now from the hierarchy we have, there is another level above 'EmpManager' and that is 'SalaryManger'. This higher level also needs to be able to edit employee information because by definition, the 'Salary Manager' can do whatever the roles below it can do, plus something extra (edit salary, EO level security in this case). So the EL securityContext.userInRole[''] will return true for and any if its parent roles. So in this case, when a user with the role 'SalaryManager' logs in he sees the link and not the readonly text becasue the expression will return true since 'SalaryManager' is a parent role of 'EmpManager'.

See the highligted EL expressions to see how application roles are referenced

That all the basics. What we have not looked at here is the integration with the WLS security infrastructure and Identity & Access Management tools like LDAP, OID and OAM.

You can download the source code here : http://myadfnotebook.googlecode.com/files/SecurityDemo.zip
To run the project, you can run the Welcome.jspx page. You will notice that some Authorization exceptions are not handled. These were left to demonstrate what happens when an authenticated user tries to access a page he is not authorized for. The exceptions can be handled by exception activities in the task flow , or the navigation links can be shows or hidden based on the authorization of a user.

By default the following users are configured (see jazn-data.xml to view/change these) :
User                  Password                   Role
department        weblogic123              DepartmentAccess
Dmanager         weblogic123              DeptManager
employee          weblogic123              EmployeeAccess
Emanager         weblogic123              EmpManager
empdept           weblogic123              DepartmentAccess & EmployeeAccess
Smanager         weblogic123              SalaryManager

Sunday, October 30, 2011

Get the ID/String Value for an LOV drop-down item though EL


In a previous post we looked at how to get the selected value or text from an LOV in our backing bean. While that approach is effective for most use-cases, there are some situations where you cannot use that approach , or using it is too cumbersome.In this post we'll look at a slightly different approach that can be used when you need to use the ID or String value in EL or you don't want to have a backing bean.

Needing to get the value in EL can be a common scenario when you are trying to extract the selected ID behind an LOV and pass it somewhere, like passing the ID to another bounded task flow. Very common use-case.

To consider an example, suppose you have an app built on the EMP and DEPT tables and you have an "Employee Edit" page. On this page, you have the department the employee belongs to, implmented as a drop down list of Departments ( LOV ). Now lets say you want to have an "Edit Dept" button next to the Department drop-down, which when clicked should take you to an "Edit Dept" page for the currently selected dept in the drop-down. This LOV drop-down on the "Edit Employee" page was created on the EMP VO, for the Dept ID attribute and would use a view-accessor on the EmpVO to map the Dept ID in the Emp Table with the Dept ID in the Dept table and pull the Dept name from that. What we need is the Department ID of the department selected in the drop-down so that we can pull up that department details in the "Department Edit" page when the user selects a department and clicks on "Edit Department".

The LOV when placed on a page, creates a list binding in the binding layer by default and as such is not very useful for us because it stores the index of the selected Item and not the underlying ID. The easiest method to get the current ID is to manually create an Attribute Binding in the pageDef that points to the DeptID on the same iterator that the list binding is pointing to. This means that when the user changes the selection in the LOV, the currency in the iterator will change and since the attribute binding is on the same iterator, the attribute binding will also change.

To get the value in EL, just refer to the attribute binding in EL and not the list binding .
Simple !

Sample application

I'm gonna re-use the sample application from the ADF Security Basics post.
http://myadfnotebook.googlecode.com/files/SecurityDemo.zip
In this application, there is a feature when editing an employee there is s a link go to the edit department page (from the employee detail page). This page has a drop down allowing you to select a department for the employee, but also a link on the side directly takes you to edit the selected department. This link is implemented using the approach described here.

Thursday, September 29, 2011

<af:query> loading screen / spinner pop-up v2.0

This is an update/follow up on a previous post about displaying a spinner or loading screen while a query is in progress. The original post can be found here. This post describes a much simpler method for getting the same result, and addresses a flaw in the original approach. Its a direct adaptation of the method described by Frank Nimphius in the ADF Code corner example.

The general idea here is to

  1. Execute a custom piece of JavaScript code when user hits 'Search' in af:query
  2. In our JS code, add a busy state listener to fire when the busy state changes.
  3. Show hide a popup based on the busy state.

The ADF code corner example is based on a normal command button. But in the case of af:query we don't have access to the command button that fires the search. In this case, we can use a Client Listener on the af:query that fires on the "query" event.  like below :


       



The example above, the JavaScript function 'fireLoadingScreen' is a custom JavaScript function and  is implemented as below :

          function fireLoadingScreen(evt){
            var source = evt.getSource();
            var popup = AdfPage.PAGE.findComponentByAbsoluteId('spinnerPopUp');
            if(popup != null ){
              AdfPage.PAGE.addBusyStateListener(popup,handleBusyState);        
              evt.preventUserInput();
            }
          }
          
          function handleBusyState(evt){
            var popup = AdfPage.PAGE.findComponentByAbsoluteId('spinnerPopUp');        
            if(popup!=null){
              if (evt.isBusy()){
                popup.show();   
              }
              else if (popup.isPopupVisible()) {
                popup.hide();
                AdfPage.PAGE.removeBusyStateListener(popup,handleBusyState);
              }
            }
          }



The complete example can be downloaded from here : http://myadfnotebook.googlecode.com/files/LoadingScreen2.0.zip

One word of caution. There are implications to using AdfPage.PAGE.findComponent in conjunction with JSF fragments. One way of working around the limitation described in this previous post is to use  

function fireLoadingScreen(evt){
        var source = event.getSource();
        var popup = source.findComponent('spinnerPopUp');
        if(popup != null ){
            popup.show();
        }
        

This uses the source UIComponent object to search for the popup component (not from the root of the document). So the search is relative to the af:query. But now you'd have no way to close the popup but to use the old backing bean based method though.

For those interested, lets look at what was actually wrong with the original approach ( other than being very convoluted )...
While the original post still holds good for a lot of situations (especially if you use jsff and are deploying the app as a portlet) , when specifically applied to af:query, it has one drawback that I recently came to know about. This drawback will be apparent only in a load balanced and highly available environment. If you use a load balancer or fail-over system, there is a chance that the user's session might be migrated to another server while a query is happening. When that happens, things go bad if you use the approach detailed in the older post . Lets see why.


Flow of events for the original solution


The original approach can be applied generically to normal command components or af:query (though there are other more declarative ways of doing this with command components). This method is useful if upon clicking a command component if you want to execute some logic in your backing bean to choose a specific pop-up/loading screen (our customers wanted different types of loading screens for various types of input specified by the user in the af:query ). What makes the implementation different for af:query vs. a normal command button is that in af:query you don't have direct access to the search button (unlike a normal command button). So we had to intercept the search action and hook in to it (step 1). The idea was to fire a user-input blocking pop-up by hooking in to the search action (but not start the search yet) (step 2), then fire the actual search from the pop-up once its visible (steps 3,4,5). In doing that we had to save the QueryEvent as a member variable in the backing bean. The query event would be provided to the method registered as the query listener (step 1), but since we don't actually do the query from that method(we just launch the popup from here) and fire the actual query from the pop-up using a second method(step 6), we need to make the QueryEvent object available to that second method (in step 6). And this is not a simple case of calling one method and passing a parameter to it. The second method is invoked using java script code to call back the backing bean. So we had to store the QueryEvent object and guess what, it is not Serializable ! So in the event a session is replicated, the serialization of the backing bean would fail. At this point one might think we can just make the QueryEvent transient and get around the serialization; But that door opens to a far more subtle and dangerous problem. Suppose we mark it transient, and there are a thousands of users on our load balanced system executing searches. The load balancer decides to move some sessions across to another server, and lets say it just happens to pick a session where a user just clicked the search button, and we've just saved the QueryEvent and opened our loading screen popup (step 1 complete). The entire session is serialized and replicated on the second server, and when the session is inflated on the second server, since we marked the QueryEvent as transient , the QueryEvent is set to null on the second server. Now things resume, but when we reach step 6 in our flow, instead of seeing a QueryEvent we would see null. What makes this problem really frustrating is that since the load balancer is involved, the issue will not be easily reproducible and it would be very difficult to trace.

As you can see, the new solution makes the whole process a lot simpler actually. As long as you have a single loading screen you want to display whenever the search button is hit, this solution is much better that the original one.