Friday, December 25, 2009

ADF Security: The Two Most Useful Security Expression - #{securityContext.regionViewable[''] and #{securityContext.taskFlowViewable['']

If you have a requirement to conditionally display a tab, a link, or a toolbar button to prevent navigation to a protected page allowed only for some specific roles then I bet that the following security expression will satisfy your need:
1)#{securityContext.regionViewable['your.page.targetPageDef']}

Chris Muir has a nice blog about conditionally displaying the global tabs of the ADF UI Shell in which I was able to comment: ADF UI Shell + ADF Security.

But if your requirement is to conditionally display a menu or a toolbar that will launch a bounded task flow (just like the in the dynamic UI Shell) then the following security expression is what you'll need:
2) #{securityContext.taskFlowViewable['/WEB-INF/yourTaskFlow.xml#yourTaskFlow']}

The expressions above will return true if you have the applicable permission, so you can use it in the rendered property of your button, tab, link, or menu. But if your requirement is to disable a component then use "!" the negation operator.

It is also likely that you will need to check the permission programmatically just like when you are a creating a dynamic tree menu based on user roles. Please see the methods below for the translation of the EL security expressions above to pure Java:
import oracle.adf.controller.security.TaskFlowPermission;
import oracle.adf.share.ADFContext;
import oracle.adf.share.security.SecurityContext;
import oracle.adf.share.security.authorization.RegionPermission;
//class declaration
...
    public boolean isRegionViewable(String pageDef) {
        if (pageDef == null) {
            return false;
        }
        RegionPermission permission =
            new RegionPermission(pageDef, RegionPermission.VIEW_ACTION);
        SecurityContext ctx = ADFContext.getCurrent().getSecurityContext();
        return ctx.hasPermission(permission);
    }

    public boolean isTaskFlowViewable(String taskflowId) {
        if (taskflowId == null) {
            return false;
        }
        TaskFlowPermission permission =
            new TaskFlowPermission(taskflowId, TaskFlowPermission.VIEW_ACTION);
        SecurityContext ctx = ADFContext.getCurrent().getSecurityContext();
        return ctx.hasPermission(permission);
    }
...
Many thanks to John Stegeman for helping me figure this out.

Oracle UI Shell: Passing Parameters to a Bounded Task Flow

The discussion below is taken from my feedback on the ADF UI Patterns in OTN forum, I just copied it here for my reference:

Hi!

I have already figured out how to pass parameters to my bounded taskflow that I intend to launch on a separate tab. It would be the same way as how the UI Shell framework passes the TabContext object to the interested taskflows. This cannot be done though without extending the dynamicTabShellDefinition.xml. I am thinking, that this pertinent requirement can easily be supported by just pre-configuring the dynamic "parametersMap" attribute of the taskFlow binding definition to a value like "#{viewScope.parametersMap}". In this case, if I have something that I need to pass as parameter to my bounded taskflows, I just need to put the object on the parametersMap in view scope. I need to test this yet though. Below is a quotation from the Fusion Developers' Guide about the parameterMap:
The <parameterMap> element specifies an EL expression that returns a java.Util.map object. The object contains task flow input parameter name/value pairs.
I have already tested my understanding on the taskFlow binding "parametersMap" attribute above and it works! First, I added an additional parameter in line with the tabContext parameter to my custom dynamicTabShellDefinition.xml. The parameter binding section will be as follows:
<parameters>
   <parameter id="tabContext" value="${viewScope.tabContext}"/>
   <parameter id="parameterMap" value="${requestScope.parameterMap}"/>
</parameters>
Note that instead of using ${viewScope.parameterMap}, I used ${requestScope.parameterMap} because it seems that when I passed a viewScope parameter from a backingBean inside one of my bounded task flows, it will not reach the initialization of my target task flow in the separate tab. Second, I redefined all my taskFlow bindings to define the "parametersMap" attribute value to "#{bindings.parameterMap}". Please see below a redefined taskFlow definition:
<taskFlow id="r0"
    taskFlowId="${viewScope.tabContext.taskflowIds[0]}"
    activation="deferred"
    xmlns="http://xmlns.oracle.com/adf/controller/binding"
    parametersMap="#{bindings.parameterMap}">
<parameters>
<parameter id="tabContext" value="${bindings.tabContext}"
         xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
</parameters>
</taskFlow>
With the steps above, I could already define any parameter that I need in the bounded taskflow: Please see below for a sample parameter definition:
<input-parameter-definition id="__2">
  <name id="__3">employeeId</name>
  <value>#{pageFlowScope.employeeId}</value>
  <required/>
</input-parameter-definition>
Just be sure that before you invoke the backing bean method that will call the TabContext addTab() method you already put the employeeId into the parameterMap and set the parameterMap into requestScope:
...
Map<String, Object> parameterMap = new HashMap<String, Object>();
parameterMap.put("employeeId",employee.getId());
JSFUtils.setRequestAttribute("parameterMap", parameterMap);//JSFUtils is a utility class from FOD
//direct or indirect call to the TabContext addTab() method here