ClearPress Framework

Authorisation

Authorisation is a bit of a thorny issue. On the most part authorisation in ClearPress is dealt with in a view's authorised method. To authorise all read and write actions for a view one could write:

sub authorised {
  return 1;
}

Obviously this is way too simple for most applications. For many, the level of authorisation needed is simply based on who the user is, if they're logged in, or at most on which usergroup the user is. $requestor usually holds the user object of the logged in user, or a 'fake' public user, otherwise (faked for the simplicity of making calls on a user object).

sub authorised {
 my $self = shift;
 my $util = $self->util;
 my $requestor = $util->requestor;

 if(!$requestor->id_user) {
  #########
  # automatically disallow anyone not logged in
  #
  return;
 }

 if($requestor->username() eq 'me@example.com') {
  #########
  # Allow me@example.com access to everything
  #
  return 1;
 }

 if($requestor->is_member_of('admin', 'superusers')) {

  #########
  # Allow all members of 'admin' and 'superusers' usergroups access to
  # everything
  #

  return 1;
 }

 my $action = $self->action;
 if($action eq 'read') {
  #########
  # Allow all logged in members read access to this view.
  # REST actions = list, read, edit, add)
  #
  return 1;
 }

 #########
 # Disallow all other access
 #
 return;
}

As the authorised method is invoked for every view it's possible to implement default access restrictions in an app::view superclass and then override the method in a derived class and call up to SUPER::authorised where necessary.

app::view
sub authorised {
  my $self = shift;
  my $util = $self->util;
  my $requestor = $util->requestor;

  if($requestor->is_member_of('admin')) {
   return 1;
  }
  return;
 }
app::view::subclass
sub authorised {
  my $self = shift;
  my $util = $self->util;
  my $requestor = $util->requestor;

  if($requestor->is_member_of('subclass admin')) {
   return 1;
  }

  return $self->SUPER::authorised();
 }

From here, authorisation can become much more complex. For example if a user is only authorised for a component in a complex page, the authorisation for that component needs to be placed in the template for the page like so:

read_complex.tt2
<h2>Page Title</h2>
<p>page content</p>
[%- IF requestor.is_member_of('admin') %]
 <p>some admin content</p>
[%- END %]