Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling authentication for JSON API requests in CakePHP REST plugin

I have being attempting to build an API for my CakePHP app using the REST plugin here: https://github.com/kvz/cakephp-rest-plugin

The reason for using this plugin is because I wanted an easy way to handle authentication with regards to API calls on protected methods and also deal with logging etc in the the future.

In order to prevent duplication, the plugin is setup as described in a previous question: CakePHP REST Plugin not returning data which has now been fixed and works.

The next part is handling authentication. I have added the following to my beforeFilter method which basically should be saying if it's a rest call and the user ins't logged in (note: that not all methods require a user to be logged in) then log them in.

if (!$this->Auth->user()) {

            if ($this->Rest->isActive()) {   

                $loginUser = $this->User->loginUser(
                    $credentials['username'],
                    AuthComponent::password($credentials['password'])
                );

                if($loginUser) {                        
                    if (!$this->Auth->login($loginUser['User'])) {
                        $msg = sprintf('Unable to log you in with the supplied credentials. ');
                        return $this->Rest->abort(array('status' => '403', 'error' => $msg));
                    }
                }

            }
        }

and for those that want to see the model call:

 public function loginUser($usernameOrEmail, $password)
    {
        return $this->find('first', array(
            'conditions' => array(
                'OR' => array(
                    'User.email' => $usernameOrEmail,
                    'User.username' => $usernameOrEmail,
                    'User.phone' => $usernameOrEmail
                ),
                'User.password' => $password
            ),
            'recursive' => -1
        ));
    }

However I can't get it to work. I'm doing the request like so for testing:

    $.ajax({
        url: 'http://domain.com/users/test.json',
        dataType: 'jsonp',
        data: { username: 'test', password: 'test' },
        headers: {
            Authorization: "TRUEREST"
        },
        success: function(response) {
            console.log(resonse);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log(jqXHR, textStatus, errorThrown);
        }
    });

The three main questions I have here are:

  • I'm manually passing the username and password here BUT is the headers part correct? The explanation regarding it is rather vague on the documentation for this here: https://github.com/kvz/cakephp-rest-plugin#authorization

  • Is $credentials['username'] going to pick it up? Is $credentials a global thing with HTTP authentication or have I missed something?

  • Is this going to log the user in every time they make a request? As it seems a little messy if that's the case.

The current code implementation errors with: Uncaught SyntaxError: Unexpected token :

and here is the JSON output which looks fine to me...

{
    "data": {
        "User": []
    },
    "meta": {
        "status": "error",
        "feedback": [{
            "message": "Log in to continue",
            "level": "error"
        }],
        "request": {
            "http_host": "domain.com",
            "http_user_agent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit\/537.22 (KHTML, like Gecko) Chrome\/25.0.1364.29 Safari\/537.22",
            "server_addr": "##.##.###.###",
            "remote_addr": "##.###.###.###",
            "server_protocol": "HTTP\/1.1",
            "request_method": "GET",
            "request_uri": "\/users\/test.json?callback=jQuery172015279368730261922_1358207116601&username=test&password=test123&_=1358207116611",
            "request_time": 1358207116
        },
        "credentials": {
            "class": null,
            "apikey": null,
            "username": null
        },
        "time_epoch": "1358207117",
        "time_local": "Mon, 14 Jan 2013 15:45:17 -0800",
        "version": "0.3"
    }
}
like image 470
Cameron Avatar asked Jan 14 '13 23:01

Cameron


1 Answers

Your issues are many and cover a broad scope. I will point you in all the directions where I see problems. The biggest issue you may find is that the user is not being found. This is because unless you are setting $credentials somewhere else in the code, they are not being set.

Missing Credentials

I don't see you setting the $credentials variable anywhere. The data option in .ajax is passed as a GET request. You may need to update from $credentials['var'] to $_GET['var']. If I remember correctly, these may also be found in $this->data->params['username'] and $this->data->params['password'].

What if user is not Auth'd

I see your if (!$this->Auth->user()), and I see where you attempt to pull the user information, but the logic seems like it would allow an un-authorized user to get through. You may want to look at that logic a little more. Here is what I would do:

if ($this->Rest->isActive()) {
     $user = $this->User->loginUser(
          $_GET['username'],
          AuthComponent::password($_GET['password'])
     );

     if (!$this->Auth->login($user)) {
          $msg = sprintf('Unable to log you in with the supplied credentials. ');
          return $this->Rest->abort(array('status' => '403', 'error' => $msg));
     }
} else {
     // handle the non-rest request
}
like image 88
Chuck Burgess Avatar answered Oct 15 '22 21:10

Chuck Burgess