New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Authentication with ACL #3
Comments
Restler has a hidden GEM called annotations support which is not yet documented fully. Reason being Restler 3.0 which is currently in production changes the syntax slightly. Any way since you have asked I will provide the code to make it work on Restler 2.0 |
Access Control using AnnotationsUse the following 3 files as an example to write your own secure version :) PHPDoc comment with the following syntax will set the properties of specified class when an instance is made by Restler
This works for Authentication classes and Format classes look at the following URI's to understand how it will work Usage Example
PHP Files
<?php
class AccessControl implements iAuthenticate{
public $requiredRole = 'admin';
function __isAuthenticated() {
//hardcoded password=>role for brevity
$roles = array('anyone'=>'user', 'secretpassword'=>'admin');
if(!isset($_GET['password']) || !array_key_exists($_GET['password'], $roles))
return FALSE;
switch ($roles[$_GET['password']]){
case 'admin':
return TRUE;
case 'user':
if($this->requiredRole=='user')return TRUE;
}
throw new RestException(401, 'Insufficient Access Rights');
}
}
<?php
class Simple {
/**
* @class AccessControl(requiredRole=user)
*/
protected function user() {
return 'allow both user & admin';
}
/**
* @class AccessControl(requiredRole=admin)
*/
protected function admin(){
return 'allow only admin';
}
}
<?php
require_once '../../restler/restler.php';
spl_autoload_register('spl_autoload');
$r = new Restler();
$r->addAPIClass('Simple','');
$r->addAuthenticationClass('AccessControl');
$r->handle(); |
Thanks for your time and code :-) Cheers. |
Just to let you know, i got it to work how i want it to. In my case in a DELETE function users are allowed only to delete their own items or able to delete any item depending on their user role. To export the userrole i put this in restler.php: $object->auth_obj = $auth_obj; Not sure if it is usefull to implement in your version ? |
I need to find a decoupled way for doing this! Authentication methods are called before the actual method so they can't have a reference to objects that are dealt within. I'm trying to avoid referring to Auth instance from the api method directly, then we cant use the method with out the auth class Maybe we can use a data class with static properties that we want to exchange, it anyway has default values so API method wont fail when Auth class is missing What do you think? <?php
class UserDetails{
static $name = 'defaultUser';
static $role = 'user';
}
//with in the Access Control method
UserDetails::$name = 'Arul';
UserDetails::$role = 'admin'; |
Sounds like a good plan. |
made a quicky which can be implemented more generic i think: <?php
//inside the Restler class definition
private static $data = array();
public static function AddObject($name,$object) {
self::$data[$name] = $object;
}
public static function GetObject($name) {
return(self::$data[$name]);
} That way you can export any object and import it anywhere you like |
Quick example: Set objects: Restler::AddObject("restler",$this);
Restler::AddObject("auth_".$auth_class,$auth_obj); and get an object: $obj = Restler::GetObject("auth_SimpleAuth");
$var = $obj->requiredRole; |
This is good, but we should do this in a generic VO kind of class instead of Restler That way your class can be reused elsewhere with out any change, just by copying the VO class along with it By the way, In case you want to do it the other way Restler places its instance as the restler property in all the restler instantiated classes including AuthClasses, APIClasses, Formats, Responder Which you may use to read properties |
Very good point :-) |
Euhm, can you give an example of your second proposal ? |
I think i understand what you mean. <?php
class ObjectStore {
private static $objstore = array();
public static function AddObject($name,$object) {
if(self::__CheckObject($name)==false) {
self::$objstore[$name] = $object;
} else {
// throw some error //
}
}
public static function GetObject($name) {
if(self::__CheckObject($name)) {
return(self::$objstore[$name]);
} else {
// throw some error //
}
}
public static function DeleteObject($name) {
unset(self::$objstore[$name]);
return(true);
}
private static function __CheckObject($name) {
return(isset(self::$objstore[$name]));
}
} The DeleteObject is optional, but can be usefull. What do you think of this? |
Did a quick fork and pushed changes. Perhaps you want to rewrite it to your own way of writing. https://github.com/electrical/Restler/commit/911df4d58acf9c7d4d22d13ee3efda5314f91791 Cheers. ps. above comment was done from my work account. forgot i was still logged in :-) |
An other question :-) <?php
/**
Only the last one works but i would like to have the option that 1 of those 2 is enough.
Any idea on that?
* @class SimpleAuth(requiredRole=install_delete)
* @class SimpleAuth(requiredRole=install_delete_all)
*/ |
try the following, it will set the value as an array
|
Works perfect :-) thanks. |
Added private $permissionRequired = '1'; into class Authentication implements iAuthenticate, before __isAuthenticated and I tried accessing $this->permissionRequired inside isAuthenticated. it always comes up with the default value '1'... even though I added
I tried a print_r($GLOBAL) inside __isAuthenticated for debugging... here is what I find...: [metadata] => Array ( [protected] => [description] => All methods in this class are protected [url] => GET /:ID [Authentication] => Array ( [requiredPermission] => 123 ) ) so I assume it does have access?? notice it got the classname Authentication correct... Am I missing something in restler? or doing something wrong? Is there any way to get the functino name or something else? are there any "public" annotations possible? like something such as /*
and then be able to pull that from the authentication and from other parts of the code (obviuosly "description" would be useless in the code, but maybe annotation[FunctionName] could be useful? |
Hi RVN-BR, Could you provide the following so we have a clearer image.
From what i see is that a change in name. You have at the top permissionRequired, and later youare talking about requiredPermission ( you changed it ) Perhaps that's whats wrong? |
sorry about that, I pasted correctly but when I typed in the echo statement i messed up when posting here... Codes: Authclass: <? php
class Authentication implements iAuthenticate{
public $requiredPermission = '1';
function __isAuthenticated() {
//return isset($_GET['key']) && $_GET['key']==SimpleAuth::KEY ? TRUE : FALSE;
echo $this->requiredPermission;
//print_r($this);
//print_r($GLOBALS);
} index.php (gateway) <? php
require_once 'APILib/restler.php';
#set autoloader
#do not use spl_autoload_register with out parameter
#it will disable the autoloading of formats
spl_autoload_register("spl_autoload");
$r = new Restler();
$r->setSupportedFormats('JsonFormat', 'XmlFormat');
$r->addAuthenticationClass('Authentication'); API class (part of the file) <?
/**
* @url GET /:ID
* @class Authentication(requiredPermission=123)
*/
function Test($ID) {
////not doing anything in here yet
return "123456";
} |
The only thing i can think of is that by putting public $requiredPermission = '1'; in top of your authentication class you over write the value that's beeing passed. What if you remove that, and try it again. The $this->requiredPermission should then be set from the api to the auth class. |
I got that from your example, where you put: public $requiredRole = 'admin'; I tried just public $requiredPermission; but still nothing... might it be something missing in my restler? I got it off here a few days ago... weird... :( I'll try more tomorrow... |
ah i see what you mean :-) forgot about that example. |
What do you mean specify the rights in the index file? test.php
|
Okay, now its making a bit more sense for me now i can see everything :-) |
New test... complete new set of files.... I give up for now :p index.php <?
require_once 'APILib/restler.php';
spl_autoload_register("spl_autoload");
$r = new Restler();
$r->setSupportedFormats('JsonFormat');
$r->addAuthenticationClass('authen'); /// I tried flipping this line with the line below so the auth would be defined after adding classes... Does it make a difference?
$r->addAPIClass('teste');
$r->handle(); teste.php <?php
class teste {
/**
* @class Authen(Level=12)
*/
protected function index($to='world') {
return "Hello $to!";
}
} authen.php <?php
class Authen implements iAuthenticate{
public $Level;
function __isAuthenticated() {
throw new RestException (401,"A level of '".$this->Level . "' is required for this");
}
} What happens is that I can never read the "Level" defined in my teste.php file ( To sum up, GET API/ gives me: { "error": { "code": 401, "message": "Unauthorized: A level of '' is required for this" } } I hope i'm making at least some sense :( sorry if I'm not....its been a long week... |
I have a feeling it never gets to the correct function and then never sets the level value. ( just a hunch; i could be wrong ) Can you remove the auth stuff first and confirm when you call the url you are reaching the right function and getting the correct output? |
Thanks a bunch for your help, once again... What do you mean doesnt get to the correct function? If I remove the ˜protecte" from the function in the API, it loads the same function, albeit without going through the authentication (using the same URL)...so the URL does seem to be mapping correctly... It is also the only function in the API (I just did some new install with blank slate...) I'm guessing my restler version is to blame.... is it after a certain release that this was implemented? could this have been accidentally disabled or removed in more recent versions? |
Wait a second... was this commited to the main branch? :o is the entire @Class notation functionality included only somewhere else than the usual restler download? i only downloaded from the main git... i assumed it had that? (although maybe not the addobject and remove object stuff that electrical contributed) |
if it goes to the right function without the authentication then the function mapping is correct. Could you try it with this version of the library? If that works we will know for sure it got broken somewhere. |
btw, the whole |
Current version of rester supports @RVN-BR let me provide the working code first. Here is the corrected and tested version of the above code. you may also download it from my dropbox Gateway (index.php) <?php
require_once '../../restler/restler.php';
require_once 'say.php';
$r = new Restler();
$r->addAuthenticationClass('Auth'); //order does not matter
$r->addAPIClass('Say'); //take note of the capitalization
$r->handle(); Auth class (auth.php) <?php
class Auth implements iAuthenticate
{
public $level = 1;
public function __isAuthenticated ()
{
throw new RestException(401,
"A level of '" . $this->level . "' is required");
}
} API class (say.php) <?php
class Say
{
/**
* @class Auth(level=12)
*/
protected function hello ($to = 'world')
{
return "Hello $to!";
}
} calling {
"error": {
"code": 401,
"message": "Unauthorized: A level of '12' is required"
}
} |
SOLVED.... phew.... Turns out addAuthenticationClass isnt "case sensitive" per se, but if you dont use the exact name, it will break the Capitalization of the addAPIClass call seems to not make any difference, even though you noted that line on your code... I will keep everything exactly like the code from now on, even though the initial API module must be called in all lower-cases, the oh well, thanks for all the help! :) |
Capitalization does make a difference in linux, unix and MacOS only on windows it is not case sensitive So here is the best practice advice to make it work in all cases
|
I am quite aware of capitalization issues in different operating systems, however the inconstansistancy of it working to call the function and to do all authentication routines, but not for passing the variable with the @Class notation is what got me.... camelCase would have been my preference for everything, I think it makes things easier to read... I understand that the php files must all be lowercase for autoload to work, but the URL could potentially follow the class name and not the filename? I'd suggest that if possible. Right now I will revert to the following conventions... lowercase filenames - myclass.php so far so good... One other alternative is using underscores... are there any restrictions with underscores? thanks! |
There are no restrictions using underscore |
Take a look at this live example if you need a Restler v3 version of the above |
Hi,
Like i said on Twitter i'm searching for a more extensive way of authentication.
In this case i want the users to authenticate them selves so i know what rights that user has.
each user can have different rights to different REST functions.
I could do HTTP AUTH, and use that to build up the ACL and check that when a REST call is done ?
Or is there a cleaner way ?
The text was updated successfully, but these errors were encountered: