Thursday 10 March 2011

JSF Security

Introduction

Securing parts of the view of a JSF application is mostly done by
calling some backing bean methods in the rendered attribute of the
components. And although it works, it isn't optimal. Security is one of
those cross-cutting concerns of applications, like logging, and one should
try to give it his own seperate place in the application. It is obvious
linked to the rest of the application but it shouldn't be mixed with the
other code like business rules.


Another important aspect is that it should be a reusable system so
that we can use it in all our applications without the need to develop it
over and over again. When I found out that CODI (MyFaces CDi extension) has the interface
org.apache.myfaces.extensions.cdi.core.api.security.AccessDecisionVoter
that can be used to place constraints on the execution of CDI methods, I
found it a good starting point for developing a reusable system.

With the help of custom components, see my previous entry, I was
able to create some tags that could restricts the visibility of any JSF
component, based on some CDI beans that are AccessDecisionVoter's.

Roles and permissions

I you search on the internet about security in web application,
you always see the usage of roles. You have the administrator or a
person from a certain department like purchase and depending on the
role; he can do certain actions within the application. But for real
life applications, I always found those roles too restrictive and not
fitting the way an application works. Within a application you have
certain actions like reading client information, creating order etc and
the user has the permission to execute this action or not. So the
security of your application should be managed by checking the
permissions of the user. For easier maintainability, one can group the
permissions into roles and the user gets one or more roles
assigned.

This way, you have a very flexible security system. If it turns
out that a certain role needs an additional permission, you can 'grant'
the permission to the role and the users automatically is allowed to do
the action. There was no need to adjust the code to allow a certain role
to do the action.

And with the AccessDecissionVoter you have the perfect setting to
implement the permission. The only method it has, is even called
checkPermission.

Permission implementation examples

First, I continue to give you some examples how you can implement
the permission checks with the CODI interface. All permissions are related
to the user who is logged on, so imagine you have somewhere a CDI bean
that gives you the currently logged on user, if any. This session scoped
bean can be injected into other CDI beans to determine the permissions the
user has.

The first example is an AccessDecissionVoter that determines if
there is a user logged in. Typically used to show first some login screen
and later on allow the user to perform some actions. The implementation
could be

@RequestScoped
@Named
public class LoggedIn extends AbstractAccessDecisionVoter
{

    @Inject
    @LoggedInUser
    private User user;

    @Override
    protected void checkPermission(InvocationContext invocationContext,
                                   Set<SecurityViolation> violations)
    {
        if (user == null) {
            violations.add(new NotLoggedInViolation());
        }
    }

}

The code is as simple as checking if the CDI bean that contains the
logged on user, is assigned. If not, no user is available and we add a
violation. The NotLoggedInViolation is a class that implements the
SecurityViolation interface which indicates the reason for the veto of the
decision voter.

The second example is a more complex one where we verify if the
logged on user has a certain permission.

@RequestScoped
@Named
public class HasCreateOrder extends AbstractAccessDecisionVoter
{

    @Inject
    @LoggedInUser
    private User user;

    @Inject
    private PermissionService permissionService;

    @Override
    protected void checkPermission(InvocationContext invocationContext,
                                   Set<SecurityViolation> violations)
    {
        if (user == null)
        {
            violations.add(new NoPermission(PermissionService.CREATE_ORDER));
        } else
        {
            if (!permssionService.hasPermission(user, PermissionService.CREATE_ORDER))
            {
                violations.add(new NoPermission(PermissionService.CREATE_ORDER));
            }
        }
    }
}

Here we ask the permissionService if the logged in user has the
permission CREATE_ORDER. Regarding the separation of concerns this is the
ideal situation. The code related to the authorization is separated from
the other business logic, but can be applied to those parts that need to
be secured.

CODI allows to secure the invocation of methods in a CDI bean as
follows:

@Named
public class FooCDIBean { 
...

   @Secured(value = {HasCreateOrder.class})
   public void someMethod() {
   ...
   }
...
}
  

the secureComponent CODI add-on allows to (re-)use these
AbstractAccessDecisionVoter implementations to secure the JSF components
in a view.

SecuredComponent

The main tag defined in the add-on is the securedComponent tag. It
can be nested within any JSF component, and changes the rendered status of
the component according to the specified decision voter which is defined.
As an example, this the code to have a welcome user text on the page, only
when there is actually a user logged in.

<h:outputFormat value="#{msg['general.label.welcome']} | ">
     <s:securedComponent voter="loggedIn"/>
     <f:param value="#{loggedInUserBean.login}"/>
 </h:outputFormat>

The <s:securedComponent /> tag changes the rendered state of
his immediate parent, in the case the outputFormat component. The string
in the voter attribute is the CDI named bean, here it is the first example
you found in the previous chapter. This is a difference with the usage by
CODI itself when we use the decisionVoter. In the @Secured annotation of
CODI, we specify a class, in the voter attribute, we specify the CDI bean
name.

When the voter isn't adding a SecurityViolation interface violation
to the list of violations, the renderer attribute keeps his original
value. If there is an addition, the component value for rendered attribute
is set to false and it is not showed. So we are still allowed to use the
rendered attribute, for example to hide the component because of some
business rules. But we no longer need the rendered attribute to hide or
show component for security reasons.

The inverse situation can also be implemented, we show a component
when the decisionVoter complains. A possible use case is the rendering of
a link to the login page in case when the user hasn't logged on yet. It
can be achieved by using the attribute not of the securedComponent
tag.

<h:commandLink value="#{msg['general.link.logon']}" action="/login.jsf">
      <s:securedComponent voter="loggedIn" not="true"/>
 </h:commandLink>

You can have the situation where the component is visible when one
of decisionVoter's 'grant' the access for the user. Therefore, the voter
attribute can have a list of CDI bean names which are decisionVoter's. If
one of those voter is making objection, it isn't adding a item to the
violastion parameter set, the component is shown.

<s:securedComponent voter="hasCreateOrder, hasAdministratorRole"/>

When the above snippet is placed in a component, the result is that
the component is shown when the user has the CREATE_ORDER permission or is
an administrator. Here there are only 2 decisionVoter's defined in the
voter attribute, but you can have any number, as long as they are
seperated by a comma. And spaces are removed because they can't be part of
the CDI Bean name.

You can also combine different decisionVoter's in the same way.
Suppose you have the use case that only an administrator who has the
CREATE_ORDER permission, should have access to a link (well not the most
realistic example), you can define the 2 decisionVoter's in the voter
attribute as above and add the combined attribute specifying a true value
for it. When the value of the attribute combined is true, all the voter's
need to allow the action, before the component stays visible.

Specifying parameters

There might occur some situations that your accessDecisionVoter
needs some parameters. Since these voters are CDI beans, you can inject
any other CDI bean that you like. And in the case where the value you want
to supply to your voter is accessible by an EL expression, but which isn't
supplied by a CDI bean, it can be supplied by nesting a <f:param>
tag inside the securedComponent tag.

An example could be:

<s:securedComponent voter="hasCreateOrder, hasAdministratorRole">
  <f:param value="#{currentOrder.orderType}"/>
</s:securedComponent>

How do we access these parameters in the AccessDecissionVoter? The
method checkPermission has the parameter invocationContext where we can
call the getMethod to retrieve an array of objects. These objects are the
parameters we have specified in the securedComponent Tag. The java code
access the parameter could then be something like this.

protected void checkPermission(InvocationContext invocationContext,
                Set<SecurityViolation> violations)
    {
        if (invocationContext.getParameters() != null)
        {
            Object parameter = invocationContext.getParameters()[0];
        ....

When multiple parameters are specified in the tag securedComponent,
the order is respected in the array within the invocationContext object.
So the first parameter can be access with .getParameters()[0], the second
on index 1 and so on.

An important aspect you need to know about the parameters is when
the evaluation of the EL is made. By default, the securedComponent
performs his functionality, verify if the user has the correct permission
and if not setting the rendered attribute to false, when the view is
build. This is, when the XHTML page is transformed to the component tree.
So it doesn't make any sense to specify for example an EL expression with
the local looping variable of a table as a parameter of an
AccessDecisionVoter. The resulting parameter value will always be null and
it will only be verified once and not for every row of the table.

However, these kinds of use cases are very interesting. It is
possible that some columns shouldn't be visible to the user depending on
the type of item that is shown in the row of the table. In the example
that I made, I have the situation that the currently logged on user can
see his own salary, but not that of other people.

For this kind of situations, there is the tag
securedComponentParameter. You can also specify it in the body of the
securedComponent tag, and it also accepts an EL in the attribute
value.

<h:dataTable value="#{employeeBean.employees}" var="employee">
            ...
         <h:column>
             <f:facet name="header">Salary</f:facet>
             <h:outputText value="#{employee.salary}">
                 <s:securedComponent voter="currentUser, hasAdministratorRole">
                     <s:securedComponentParameter value="#{employee}"/>
                 </s:securedComponent>
             </h:outputText>
         </h:column>

         ...

The result of the EL expression of the attribute with the
securedComponentParameter is also accessible in the getParameters method
of the invocationContext object. There is no difference with the f:param
tag in that sense. But internally, the functionality of the
securedComponent is no longer executed at the time the component tree is
build, but during the rendering of the tree to HTML (or whatever output
you have).

Example code

You can find the code for the CODI add-on in the bitbucket
repository https://bitbucket.org/os890/codi-addons in the directory
secure_component. There is also en example available in that directory.
The application allows you to log on with any user name. The page with the
employee list, shows only the salary for the logged on user or when you
are an administrator (log in with a username that starts with
admin).

Known issues

Well, the most important remark I have to make here is that is was
designed for the XHTML/Facelets way of working with JSF 2.0. I'm currently
investigating if something similar is possible with the JSP
variant.

Conclusion

With this secure component CODI add-on, you can implement a fine
security system for JSF components which is separate from the other
bussiness code of your application. Since security is one of those
cross-cutting concerns, you try to separate it from the real business
code. There is support for EL expressions within a looping construct like
a dataTable with the special tag securedComponentParameter. The add-on is
available under the Apache OpenSource license v2. Have fun.

2 comments:

  1. thanks a lot.
    Why this is not in CODI official??

    looks very good!!!

    ReplyDelete
  2. First of all thanks for this excellent work! I'm trying to run the codi-addons example on WebSphere 8 but I noticed a strange behavior. The securedComponent in the employee table doesn't always work, actually most of the time the currentUser voter is not processed but sometime it is and the table shows only the salary of the current user. Any idea ? Thx again!

    ReplyDelete