Security

Application managed security can be implemented using Controller hierarchies and lifecycle features.

Introduction

All aspects of web application security of course also pertain to Civilian applications, as do established security techniques and solutions.

In addition we present techniques how to implement application managed security based on features of the Controller class.

Container and application managed security

Authentication and access control are two main aspects of application security. In the context of web applications they translate into questions such as
  • how to authenticate clients which make a request?
  • how to present a login form?
  • how to implement session management?
  • how to restrict access to resources?
  • how to create responses tailored to access rights?
  • etc.
Container managed security is a solution to enforce authentication and access control at the container level whereas the application does not need to take care of these tasks. In a servlet environment this is done using declarative definitions, e.g. in the web.xml.

But more complex applications often require application managed security – security measures are implemented and enforced by the application. Here are two use cases which cannot be addressed by declarative definitions in a servlet container:

  • Access to a resource is always granted but the returned representation depends on access rights of the user who is making the request. E.g. in a returned HTML page specific menu items are only included for specific user roles, page parts are different, etc.
  • A resource displays data which is identified by a request parameter. Access control restricts an user to certain partitions of the whole data space. Therefore requests are either processed or rejected based on the request parameter. For instance (for a path parameter encoding a customer id) a user may access the resource /customers/1345 but not /customers/7890.
Libraries like Spring Security or Apache Shiro can help you to implement application managed security. In the following we discuss additional possibilities to implement authentication and access control in your application using Controller features.

Use controller architecture for security

Requests to dynamic resources are processed by Controllers. The interplay of controller inheritance and invocation allows for elegant solutions how to implement and enforce authentication and access control within your application.

The CRM sample is used to exemplify the discussion.

Controller inheritance

Controller classes are derived from Controller, but you can also introduce base controller classes derived from Controller specific to your application.
Why would you want to do this? Of course to inherit functionality from base classes.

Now to an important observation: If the resource URLs exposed by your application form a well designed URL tree it will most likely align well with a controller hierarchy:

Controller class maps to resource
abstract          CrmController
+- abstract       SecuredController
   +-             IndexController
/
   +- abstract    users.UsersController
      +-          userse.IndexController
/users
      +- abstract users.id.UserController
         +-       users.id.IndedxController
/users/{:userId}
(using +- as inheritance relation and omitting the package prefix org.civilian.samples.crm.web.root)

We will use this feature to inherit security related functionality.

Controller invocation

Controllers have a defined lifecycle and invocation: A controller instance is created to process a single request. Controllers define action methods (for different RESTful scenarios) which are the entry points for processing. Before and after a controller action method is invoked, initialization and cleanup methods defined by the Controller base class are called.

Our strategy to implement authentication and access control is based on the initialization method Controller.checkAccess() which is called before the negotiated Controller action method.
If checkAccess() commits the response, e.g. by sending a redirect or an error, the controller action method is not invoked.

Prevent unauthenticated access using Controller.checkAccess()

Class org.civilian.samples.crm.web.root.CrmSecuredController of the CRM sample is the common base class for all controllers whose resource is behind the login wall.
It implements checkAccess() and
  • tests if the request is made by an authenticated user (testing the existence of a session attribute).
  • If not, it sends a 401 unauthorized error (for ajax requests) or a redirect to the /login resource (for non-ajax requests).
  • If yes, it initializes a SessionUser property which is available to all derived classes.
CrmSecuredController.checkAccess() is declared final, therefore it is guaranteed that no resource behind the login wall can be accessed without proper authentication.

Implement and enforce any access control using Controller.checkAccess()

Naturally this technique can be used to implement any access control. As a second example the CRM sample allows access to resources /users/* only to users with the administrator role.
Again a common Controller base class org.civilian.samples.crm.web.root.users.UsersController for these resources exists.
It inherits from CrmSecuredResource – that already guarantees only authenticated access to resources /users/*.
But CrmSecuredResource.checkAccess() is declared final (to have a strong guarantee). To allow for additional access control checks, CrmSecuredResource declares the method checkCrmAccess() which is called when the request is properly authenticated.
Now, UsersController uses this method to implement its check for the admin role.
If derived classes would require another more specific access check, we could apply the technique again and provide for instance a method checkUserAccess().