3

I'm currently developing a restful/stateless api in cakephp which uses tokens (at the moment) and should use rolling tokens (like suggested here from g-shearer) in the future. My current implementation works, but i'm really concerned if i've implemented everything the right way (auth components especially custom auth components seem really confusing to me)

PS: I'm using the current version of cakephp (2.5.1).

1: I've created the file TokenAuthenticate.php in Controller/Component/Auth:

<?php

App::uses('BaseAuthenticate', 'Controller/Component/Auth');

class TokenAuthenticate extends BaseAuthenticate {

public function authenticate(CakeRequest $request, CakeResponse $response) {
}

public function getUser(CakeRequest $request) {
    //set values from request headers
    $publictoken = $request->header('Security-Public-Token');
    $accesstoken = $request->header('Security-Access-Token');
    $timestamp = $request->header('Security-Timestamp');
    // check if required header fields are set
    if (empty($publictoken) || empty($accesstoken) || empty($timestamp)) {
        return false;
    }
    // init required token model
    $Token = ClassRegistry::init('Token');
    //check if token pair exists
    if ($dbtoken = $Token->findByPublic($publictoken)) {
        if ($accesstoken == md5($dbtoken['Token']['private'] . $timestamp)) {
            //valid token - return user
            $User = ClassRegistry::init('User');
            $dbuser = $User->findById($dbtoken['Token']['user_id'])['User'];
            return $dbuser;
        } else {
            //invalid token
            return false;
        }
    } else {
        //invalid token pair
        return false;
    }
}

public function unauthenticated(CakeRequest $request, CakeResponse $response) {
    return true;
}

}

?>

then i've added the following to my controller:

class UsersController extends AppController {
public $uses = array('User', 'Token');
public $components = array('Auth' => array('authenticate' => array('Token')));

public function beforeFilter() {
    parent::beforeFilter();
    AuthComponent::$sessionKey = false;
    $this->Auth->autoRedirect = false;
    $this->Auth->allow('login', 'register');
}

in my actions i check the status like so:

if (!$this->Auth->loggedIn()) {
        $this->set(array('error' => 'INVALID_AUTHENTIFICATION'));
        $this->render('view');
    }

So I can set a custom error and output it without being redirected to the login action (note the unauthenticated function in my tokenauthentication file which returns true - so cakephp does not redirect you)

I think the login process should happen in the authenticate function of my TokenAuthenticate file and not in the login action of my controller, or am i wrong? What is the correct way to achieve this goal?

PS: How would it be possible to add a new token pair (to every authenticated output) automatically with cakephp so the tokens are 'rolling'?

The whole api output is json encoded if that matters

also cakephp still sets a cookie sometimes even though i disabled this (AuthComponent::$sessionKey = false;). How to stop this?

EDIT: So I've added an beforeRender() function to my userscontroller and now the tokens are rolling (Y)

    //renew tokens
public function beforeRender() {
    //only add tokens if logged in
    if ($this->Auth->loggedIn()) {
        //find old token
        $oldToken = $this->Token->findByUser_id($this->Auth->user('id'));
        //delete old token
        $this->Token->delete($oldToken['Token']['id']);
        //create new token pair
        $this->Token->create();
        $this->Token->save(array(
            'user_id' => $this->Auth->user('id'),
            'public' => Security::hash(substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$') , 0 , 15 )),
            'private' => Security::hash(substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$') , 0 , 15 ))
        ));
        //set it for the view
        $this->set(array('token' => $this->Token->read()));
    }
}

Is this the right way to implement something like this? I always want to do things the right and 'perfect' way so any criticsm is welcome :)

Community
  • 1
  • 1
Omegavirus
  • 277
  • 4
  • 16
  • also cakephp still sets a cookie sometimes even though i disabled this (AuthComponent::$sessionKey = false;). How to stop this? – Omegavirus Jun 06 '14 at 11:44
  • 1
    Having `AuthComponent::$sessionKey = false;` will prevent AuthComponent from starting session but any attempt to access session info anywhere else in your app will auto start session. – ADmad Jun 06 '14 at 13:22
  • You mean calling something from $this->Session? In my whole code there isn't something like this.. But good to know that! – Omegavirus Jun 06 '14 at 21:19
  • Okay. If you find out what's triggering the setting of cookie be sure to post a bug report :) – ADmad Jun 07 '14 at 06:08
  • i deleted the cookie again and till now it hasn't reappeared. that's strange because i didn't change anything in my code. maybe the cookie manager extension for firefox is a little bit buggy. if i find something out i will post the bug report :) what do you say to my auth implementation? – Omegavirus Jun 07 '14 at 09:03
  • 1
    Your `TokenAuthenticate` class is fine. Just instead of hard coding the model name `Token` set `userModel` in authenticate provider config. – ADmad Jun 07 '14 at 12:05

0 Answers0