evan108108 / RESTFullYii

RESTFull API for your Yii application

Home Page:http://evan108108.github.com/RESTFullYii/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unauthorized message while using restfullyii

ctippur opened this issue · comments

Hello,
I have seen several posts on this issue but I am unable to make my code work. I get a

Curl request:

curl -i -H "Accept: application/json" -H "HTTP_X_REST_USERNAME: admin" -H "HTTP_X_REST_PASSWORD: admin" http://localhost:8888/workspace/pharma/index.php/api/appUser
HTTP/1.1 200 OK
Date: Thu, 14 Aug 2014 09:16:09 GMT
Server: Apache/2.2.26 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.6 PHP/5.5.10 mod_ssl/2.2.26 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5.18.2
X-Powered-By: PHP/5.5.10
Set-Cookie: PHPSESSID=d67b2fd91bcdb8cbb51b6aa794174506; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 104
Content-Type: text/html
{"success":false,"message":"Unauthorized","data":{"errorCode":401,"message":"Unauthorized"}}

Here is my controller:

'RestfullYii.actions.ERestActionProvider', ); } /** * Specifies the access control rules. * This method is used by the 'accessControl' filter. * @return array access control rules */ public function accessRules() { return array( array('allow', // allow all users to perform 'index' and 'view' actions 'actions'=>array('index','view'), 'users'=>array('*'), ), array('allow', // allow authenticated user to perform 'create' and 'update' actions 'actions'=>array('create','update'), 'users'=>array('@'), ), array('allow', // allow admin user to perform 'admin' and 'delete' actions 'actions'=>array('admin','delete'), 'users'=>array('admin'), ), array('allow', 'actions'=>array('REST.*','REST.GET', 'REST.PUT', 'REST.POST', 'REST.DELETE'), 'users'=>array('*'), ), array('deny', // deny all users 'users'=>array('*'), ), ); ``` /\* return array( array('allow', 'actions'=>array('REST.GET', 'REST.PUT', 'REST.POST', 'REST.DELETE'), 'users'=>array('_'), ), array('deny', // deny all users 'users'=>array('_'), ), ); */ } ``` public function restEvents() { $this->onRest('model.instance', function() { return new User(); }); $this->onRest('req.auth.uri', function($uri, $verb) { switch ($verb) { case 'GET': //return Yii::app()->user->checkAccess('REST-GET'); break; case 'POST': return Yii::app()->user->checkAccess('REST-POST'); break; case 'PUT': return Yii::app()->user->checkAccess('REST-PUT'); break; case 'DELETE': return Yii::app()->user->checkAccess('REST-DELETE'); break; default: return false; break; } }); }); $this->onRest('post.filter.req.auth.ajax.user', function($validation) { return true; }); $this->onRest('req.post.user.render', function($data) { echo CJSON::encode($data); //The $data should contain username and password. //Login the user here. Should be easy. //Then render a response }); $this->onRest('model.with.relations', function($model) { $nestedRelations = []; return $nestedRelations; }); } ``` } I have the authentication part on config/main.php ``` 'params'=>array( 'RestfullYii' => array( 'req.auth.ajax.user' => function(){ if(isset($_SERVER['HTTP_X_REST_USERNAME']) and isset($_SERVER['HTTP_X_REST_PASSWORD'])) { $username = trim($_SERVER['HTTP_X_REST_USERNAME']); $password = trim($_SERVER['HTTP_X_REST_PASSWORD']); $identity=new UserIdentity($username,$password); if($identity->authenticate()){ Yii::app()->user->login($identity,0); return true; } else{ return false; } } return false; }, ), ), ```

Interesting ..

I think I made some progress.

The curl needed to be HTTP_HTTP_X_REST_USERNAME

But now I see that all requests are allowed

$this->onRest('req.auth.ajax.user', function() {

          if(isset($_SERVER['HTTP_HTTP_X_REST_USERNAME']) and isset($_SERVER['HTTP_HTTP_X_REST_PASSWORD'])) {
                    $username = trim($_SERVER['HTTP_HTTP_X_REST_USERNAME']);
                    $password = trim($_SERVER['HTTP_HTTP_X_REST_PASSWORD']);
                    $identity=new UserIdentity($username,$password);
                    if($identity->authenticate()){
                        Yii::app()->user->login($identity,0);
                        return true;
                    }
                    else{
                        // Adding Debug
                        echo "RETURNING FALSE"
                        return false;
                    }
                }
                return false;
        });

With curl, I get a response with RETURNING FALSE but I get a successful return of all data. Authentication is going thro but somewhere it is getting lost.

Even though
$this->onRest('req.auth.ajax.user', function() { ..

is returning false, the user with wrong credentials get authenticated.

Curl with wrong password ..

curl -i -H "Accept: application/json" -H "HTTP_X_REST_USERNAME: admin" -H "HTTP_X_REST_PASSWORD: admin" http://localhost:8888/workspace/pharma/index.php/api/appUser

HTTP/1.1 200 OK
Date: Thu, 14 Aug 2014 18:20:18 GMT
Server: Apache/2.2.26 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.6 PHP/5.5.10 mod_ssl/2.2.26 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5.18.2
X-Powered-By: PHP/5.5.10
Set-Cookie: PHPSESSID=460d413be8ea3d2a5d7cfeafaa6bf5df; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 1573
Content-Type: text/html

HERE11{"success":true,"message":"Record(s) Found","data": ...

HTTP_X_REST_PASSWORD is wrong. If you read the README you will see it should be "X_REST_PASSWORD" & "X_REST_USERNAME"*

* For Apache 2.4+:

You should replace the underscores with dashes:
Change this : "X_REST_PASSWORD" to this: "X-REST-PASSWORD"
Change this : "X_REST_USERNAME" to this: "X-REST-USERNAME"
YOU DO NOT CHANGE NEED TO CHANGE THE PHP CODE!!!!
Apache WILL TRANSLATE THE DASHES INTO UNDERSCORES WHEN EXPOSED TO PHP.
*For nginx:

You must set "underscores_in_headers on" see 

http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers

Your seeing the wrong event ("req.auth.ajax.user"). Lets look at the event that decides which authentication method to use.

/**
 * req.auth.type
 *
 * @return (Int) The request authentication type which may be 'USERPASS' (2), 'AJAX' (3) or 'CORS' (1)
 */
$onRest(ERestEvent::REQ_AUTH_TYPE, function($application_id) {
  if(isset($_SERVER['HTTP_X_'.$application_id.'_CORS']) || (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'OPTIONS')) {
    return ERestEventListenerRegistry::REQ_TYPE_CORS;
  } else if(isset($_SERVER['HTTP_X_'.$application_id.'_USERNAME']) && isset($_SERVER['HTTP_X_'.$application_id.'_PASSWORD'])) {
    return ERestEventListenerRegistry::REQ_TYPE_USERPASS;
  } else {
    return ERestEventListenerRegistry::REQ_TYPE_AJAX;
  }
});

Take notice that USERPASS (curl) auth will only be triggered when both "X_REST_PASSWORD" & "X_REST_USERNAME" are set (note: php/apache/nginx will automatically add the prefix "HTTP_", thus you should not add this to your curl request).

I am very confident that when you get php to recongnize "$_SERVER['HTTP_X_REST_PASSWORD']" & "$_SERVER['HTTP_X_REST_USERNAME']" then everything will work just fine.

Something to keep in mind. RESTFullYii does not "log" any users in out of the box and only does basic auth, however you should have all the event hocks you need to create a robust login and authentication system.

Evan,

Thanks for the quick response. I will give it a shot tonight.

  • S

@ctippur :> Were you able to get this working?

Evan,

You are right but if I try with

$ curl -i -H "Accept: application/json" -H "X_REST_USERNAME: admin" -H "X_REST_PASSWORD: abc123" http://localhost:8888/workspace/pharma/index.php/api/appUser
HTTP/1.1 401 Unauthorized
Date: Tue, 19 Aug 2014 02:17:07 GMT
Server: Apache/2.2.26 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.6 PHP/5.5.10 mod_ssl/2.2.26 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5.18.2
X-Powered-By: PHP/5.5.10
Set-Cookie: PHPSESSID=092f2e8fff06e8f946b0113067ad2d36; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 92
Content-Type: application/json

{"success":false,"message":"Unauthorized","data":{"errorCode":401,"message":"Unauthorized"}}

I get unauthorized...

@ctippur :> Yes this is most likely correct because you will need to modify these two events:

$this->onRest('req.auth.username', function(){
    return 'admin@restuser';
});

$this->onRest('req.auth.password', function(){
    return 'admin@Access';
});

As you can see the username and password are hardcoded (which you should change). Most-likely, I suspect you will want to override the "req.auth.user" event and do your own custom logic. If you take a look at the event bellow you can see that it returns a boolean (returns True if both X_REST_USERNAME & X_REST_PASSWORD match 'req.auth.username' & 'req.auth.password' and FALSE if not). This is intentionally a very limited and insecure system, so as to encourage you to change it to meet your needs. Its very simple to change the auth behavior, as you should have all the information you need and all you have to do is return a bool.

$this->onRest('req.auth.user', function($application_id, $username, $password) {
    if(!isset($_SERVER['HTTP_X_'.$application_id.'_USERNAME']) || !isset($_SERVER['HTTP_X_'.$application_id.'_PASSWORD'])) {
                return false;
            }
    if( $username != $_SERVER['HTTP_X_'.$application_id.'_USERNAME'] ) {
        return false;
    }
    if( $password != $_SERVER['HTTP_X_'.$application_id.'_PASSWORD'] ) {
        return false;
    }
    return true;
});

@ctippur :> has this now been resolved?

Thx Evan. Please close the issue.