Writing an authenticator for the Access Management System
The Access Management System comes with several authenticators, but can be extended by adding more.
An authenticator must satisfy the following condition:
- An authenticator must be placed in the same directory as other authenticator at
engine/models/authenticators
and comes with the prefix of_authenticator
at the end. (eg facebook_authenticator.php) - An authenticator must extends the
Authenticator
class and include theengine/models/authenticator.php
file - An authenticator must have a function called
authenticate
that will execute$this->return_roles($role)
where$role
is the role that successfully authenticated to, or else throw an exception that will be catch and return as an error message
Take for instance the Facebook Authentication file engine/models/authenticators/facebook_authenticator.php
<?php
/**
* Authenticator for Social Accounts / Facebook
* @author Minh Duc Nguyen <minh.nguyen@ands.org.au>
*/
require_once('engine/models/authenticator.php');
class Facebook_authenticator extends Authenticator {
public function authenticate() {
$provider = 'Facebook';
$this->load->library('HybridAuthLib');
try{
$service = $this->hybridauthlib->authenticate($provider);
if($service->isUserConnected()) {
$user_profile = $service->getUserProfile();
$access_token = $service->getAccessToken();
$access_token = $access_token['access_token'];
$allow = array('identifier', 'displayName', 'photoURL', 'firstName', 'lastName', 'email');
foreach($user_profile as $u=>$thing){
if(!in_array($u, $allow)) unset($user_profile->{$u});
}
//check if there's an existing profile
$user = $this->cosi_db->get_where('roles', array('role_id'=>$user_profile->identifier, 'authentication_service_id'=>'AUTHENTICATION_SOCIAL_FACEBOOK'));
if($user->num_rows() > 0) {
//found existing user, maybe updating some logs here
} else {
//create a new role
$data = array(
'role_id' => $user_profile->identifier,
'role_type_id' => 'ROLE_USER',
'authentication_service_id' => 'AUTHENTICATION_SOCIAL_FACEBOOK',
'enabled' => DB_TRUE,
'name' => $user_profile->displayName,
'oauth_access_token' => $access_token,
'oauth_data' => json_encode($user_profile),
'email' => $user_profile->email
);
$this->cosi_db->insert('roles',$data);
$user = $this->cosi_db->get_where('roles', array('role_id'=>$user_profile->identifier, 'authentication_service_id'=>'AUTHENTICATION_SOCIAL_FACEBOOK'));
}
$user = $user->row(1);
$this->return_roles($user);
}
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
public function load_params($params) {}
private function check_req() {}
}
The Facebook authenticator will automatically create a new role with the role ID as the user identifier and the source authentication_service_id
as AUTHENTICATION_SOCIAL_FACEBOOK
or will return the role if it is already authenticated.
Note that the load_params($params)
and check_req()
function are overwritten and do nothing, because this is an OAuth 2.0 authentication. Username/Password authentication will have the ability to load the parameters that require checking and check them before doing authentication
public function load_params($params) {
$this->params = $params;
$this->check_req();
}
private function check_req() {
$required_fields = array('username', 'password');
foreach($required_fields as $req) {
if(!isset($this->params[$req]) || trim($this->params[$req])==''){
throw new Exception('Field '.$req.' is required');
}
}
}
So username
and password
can be checked if it is passed in or not.
Also, there are other functions/hook that can be used within the authenticator to manage redirection after an authentication success, they are post_authentication_hook
and redirect_hook
, these are automatically called in the return_roles
function, but if one wishes to overwrite the redirect functionality (for eg. redirect to a different domain), they can be overwritten without problem, as the user is already authenticated via the PHP SESSION.