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/authenticatorsand comes with the prefix of_authenticatorat the end. (eg facebook_authenticator.php) - An authenticator must extends the
Authenticatorclass and include theengine/models/authenticator.phpfile - An authenticator must have a function called
authenticatethat will execute$this->return_roles($role)where$roleis 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.