Skip to content

Instantly share code, notes, and snippets.

@zombor
Created May 9, 2011 13:42
Show Gist options
  • Save zombor/962539 to your computer and use it in GitHub Desktop.
Save zombor/962539 to your computer and use it in GitHub Desktop.
Controller/Action ACL logic
<?php
/**
* Extension to Controller_Website that enforces authentication
*
* @package
* @author Jeremy Bush
* @copyright (c) 2011 Jeremy Bush
*/
class Controller_Website_Authenticated extends Controller_Website
{
/**
* Overload before to force authentication
*
* @return null
*/
public function before()
{
parent::before();
try
{
// We need to be at least authenticated to see this
Auth::instance()->get_user()->assert('use_authenticated');
// Otherwise fall back to auth checks
$this->check_auth();
}
catch (Policy_Exception $e)
{
// See if we have a specific place to go first
$directory = Request::current()->directory()
? Request::current()->directory().'_' : '';
$message = $directory.
Request::current()->controller().
'_'.Request::current()->action();
$message = Kohana::message('policy', $message.'.'.Model_ACL_Role::LOGIN);
if ($message AND is_array($message))
{
Session::instance()->set('requested_page', $this->request->uri());
Session::instance()->set('flash_message', $message['message']);
$this->request->redirect($message['route']);
}
$this->request->action('unauthorized');
Session::instance()->set('requested_page', $this->request->uri());
}
catch (Authorization_Exception $e)
{
// See if we have a specific place to go first
$directory = Request::current()->directory()
? Request::current()->directory().'_' : '';
$message = $directory.
Request::current()->controller().
'_'.Request::current()->action();
$message = Kohana::message('policy', $message.'.'.Model_ACL_Role::LOGIN);
if ($message AND is_array($message))
{
Session::instance()->set('requested_page', $this->request->uri());
Session::instance()->set('flash_message', $message['message']);
$this->request->redirect($message['route']);
}
$this->request->action('unauthorized');
Session::instance()->set('requested_page', $this->request->uri());
}
}
/**
* Prompts a user to login if they don't have access
*
* @return null
*/
public function action_unauthorized()
{
$this->response->status('403');
Session::instance()->set(
'flash_error', 'Please login to view this page.'
);
$this->view = NULL;
$this->template = Request::factory('users/login')->execute()->body();
}
}
<?php
return array(
'message_compose' => array(
Model_ACL_Role::LOGIN => array(
'route' => Route::get('user login')->uri(),
'message' => 'Please login to view your messages.',
),
),
'users_lists_create' => array(
Model_ACL_Role::LOGIN => array(
'route' => Route::get('user register')->uri(),
'message' => 'Please create an account to make a list.',
),
),
'users_account' => array(
Model_ACL_Role::LOGIN => TRUE,
),
);
<?php
abstract class Controller_Website extends Controller
{
protected $prompt_login = TRUE;
public function before()
{
parent::before();
// Make sure they can even use this website
Auth::instance()->get_user()->assert('use_website');
$this->user = Auth::instance()->get_user();
$directory = Request::current()->directory() ? Request::current()->directory().'_' : '';
$view_name = 'View_'.$directory.Request::current()->controller().'_'.Request::current()->action();
if(Kohana::find_file('classes', strtolower(str_replace('_', '/', $view_name))))
{
$this->template = $this->view = new $view_name;
}
}
public function after()
{
if (isset($this->view))
{
$this->view->errors = Session::instance()->get_once('flash_error');
$this->view->flash_message = Session::instance()->get_once('flash_message');
$this->response->body($this->view->render());
}
else
$this->response->body($this->template);
}
/**
* Authorization method for all controller classes.
*
* @throws Authorization_Exception
*
* @return null
*/
public function check_auth()
{
// The parent call is always right
if ( ! $this->request->is_initial())
{
return;
}
$status = TRUE;
$user = Auth::instance()->get_user();
$policy_name = Request::current()->controller().
'_'.Request::current()->action();
// This can be a blacklist or whitelist method, depending on how the
// policy class is setup
try
{
try
{
// look for the specific method
$refl = new ReflectionClass('Policy_'.$policy_name);
$class = $refl->newInstanceArgs();
$status = $class->execute($user);
if (TRUE === $status)
return;
}
catch (ReflectionException $ex)
{
// otherwise try and look for one for the whole controller
$refl = new ReflectionClass(
'Policy_'.Request::current()->controller()
);
$class = $refl->newInstanceArgs();
$status = $class->execute($user);
if (TRUE === $status)
return;
}
}
// try and find a message based policy
// This is basically a blacklist method
catch (ReflectionException $ex)
{
$status = FALSE;
$no_policy = FALSE;
// If there's no policy message file, assume there's no auth needed
if ( ! Kohana::message('policy', $policy_name, FALSE))
{
$no_policy = TRUE;
}
// If there's no policy message file, assume there's no auth needed
if (
$no_policy
AND ! Kohana::message(
'policy', Request::current()->controller(), FALSE
)
)
{
$no_policy = TRUE;
}
else
{
$no_policy = FALSE;
}
if ($no_policy)
{
return;
}
// Try each of this user's roles to match a policy
if ( ! Auth::instance()->logged_in())
{
if (Kohana::message(
'policy',
$policy_name.'.'.Model_ACL_Role::LOGGED_OUT,
FALSE
)
)
{
$status = TRUE;
}
if (Kohana::message(
'policy',
Request::current()->controller().
'.'.Model_ACL_Role::LOGGED_OUT,
FALSE
)
)
{
$status = TRUE;
}
if ($status)
return;
}
foreach ($user->find_related('roles') as $role)
{
if (Kohana::message(
'policy',
$policy_name.'.'.$role->id,
FALSE
))
{
$status = TRUE;
}
if (Kohana::message(
'policy',
Request::current()->controller().'.'.$role->id,
FALSE
)
)
{
$status = TRUE;
}
if ($status)
return;
}
}
if (TRUE === $status)
return;
// We don't know what kind of specific error this was
if (FALSE === $status)
{
$status = Policy::GENERAL_FAILURE;
}
Policy::$last_code = $status;
throw new Authorization_Exception(
'Could not authorize policy :policy',
array(':policy' => $policy_name),
$status
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment