0

I'm testing my API and there's a login method for OAuth that I can't seem to properly test due to how it will not read $_GET values of a variable when POSTing.

The login method. Basically $OAuthParams doesn't get set when using POST because getAuthorizeParams() uses $_GET. So I want to fill/mock either $_GET or $OAuthParams.

public function login () {
    $OAuthParams = $this->OAuth->getAuthorizeParams();
    if ($this->request->is('post')) {
        $this->validateRequest();
        $loginData = array('User' => array(
                'username' => $this->request->data['User']['username'],
                'passwd' => $this->request->data['User']['passwd']
            ));
        //Attempted login
        if ($this->Auth->login($loginData['User'])) {
            unset($loginData);
            $userData = $this->User->find('first',array(
                'conditions' => array(
                    'User.username' => $this->request->data['User']['username']
                ),
                'fields' => array('username','name','id','banned','active','role','private'),
                'recursive' => -1
            ));

            $this->Session->write('Auth.User',$userData['User']); //Update the session

            //Write this to session so we can log them out after authenticating
            $this->Session->write('OAuth.logout', true);

            //Write the auth params to the session for later
            $this->Session->write('OAuth.params', $OAuthParams);

            //Off we go
            return $this->redirect(array('action' => 'authorize'));
        } else {
            $this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth');
        }
    }
    $appName = $this->applicationDetails['name'];
    $this->set(compact('OAuthParams','appName'));
}

The current test method.

/**
 * testAccessToken method
 * 1. Get the authorization code (/oauth/authorize?response_type=code&client_id=CLIENT_ID&client_secret=CLIENT_SECRET)
 * 2. Retrieve the token (/oauth/token?grant_type=authorization_code&code=CODE_RETURNED&client_id=CLIENT_ID&client_secret=CLIENT_SECRET)
 * 3. Parse the token from the returned data
 * @return void
*/
public function testAccessToken(){
    //@link http://stackoverflow.com/questions/8183396/dealing-with-security-component-in-a-cakephp-2-test-case
    $this->OAuth = $this->generate('OAuth', array(
        'components' => array(
            'Security' => array('_validatePost'),
        )
    ));
    $this->OAuth->Security->expects($this->any())
        ->method('_validatePost')
        ->will($this->returnValue(true));

    $get_data = array(
        'response_type' => 'code',
        'client_id' => getenv('THREE_SCALE_APP_ID'),
        'client_secret' => getenv('THREE_SCALE_APP_KEY'),
    );
    $post_data = array(
        'User' => array(
            'username' => 'test_user_1',
            'passwd' => 'tester'
        )
    );

    $resultPost = $this->testAction(
        '/oauth/login', 
        array(
            'method' => 'post',
            'data' => $post_data
        )
    );
    debug($resultPost);

    $data_for_code = array(
        'accept' => 'Yep',
        'Authorize' => array(
            'client_id' => getenv('THREE_SCALE_APP_ID'),
            'client_secret' => getenv('THREE_SCALE_APP_KEY'),
            'response_type' => 'code',
            'state' => '',
            'scope' => ''
        )
    );
    $code = $this->testAction(
        '/oauth/authorize', 
        array(
            'data' => $data_for_code, 
            'method' => 'post'
        )
    );
    debug($code);
    /*$data_for_token = array(
        'grant_type' => 'authorization_code',
        'code' => $code,
        'client_id' => getenv('THREE_SCALE_APP_ID'),
        'client_secret' => getenv('THREE_SCALE_APP_KEY')
    );
    $token = $this->testAction(
        '/oauth/token', 
        array(
            'data' => $data_for_token, 
            'method' => 'post'
        )
    );*/
    //debug($token);
}

Tried the following with no luck.

$this->OAuth = $this->generate(
    'OAuth',
    array(
        'components' => array(
            'Security' => array( '_validatePost' ),
            'Auth' => array('loggedIn','user')
        ),
        'methods' => array(
            'getAuthorizeParams'
        )
    )
);
$data = array(
    'response_type' => 'code',
    'client_id' => getenv('THREE_SCALE_APP_ID'),
    'client_secret' => getenv('THREE_SCALE_APP_KEY')
);
$this->OAuth->expects($this->any())
    ->method('getAuthorizeParams')
    ->will($this->returnValue($data));

$loginData = array(
    'User' => array(
        'client_id' => getenv('THREE_SCALE_APP_ID'),
        'client_secret' => getenv('THREE_SCALE_APP_KEY'),
        'response_type' => 'code',
        'state' => '',
        'scope' => '',
        'redirect_uri' => 'https://myurl.com/api/myCallbackMethod',
        'username' => 'test_user_1',
        'passwd' => 'tester'
    )
);

//test login action
$resultPost = $this->testAction(
    '/oauth/login?response_type=code&client_id=' . getenv('THREE_SCALE_APP_ID') . '&client_secret=' . getenv('THREE_SCALE_APP_KEY'), 
    array(
        'method' => 'post',
        'data' => $loginData
    )
);
debug($resultPost);

$data = array(
    'accept' => 'Yep',
    'Authorize' => array(
        'client_id' => getenv('THREE_SCALE_APP_ID'),
        'client_secret' => getenv('THREE_SCALE_APP_KEY'),
        'response_type' => 'code',
        'state' => '',
        'scope' => ''
    )
);

$result = $this->testAction(
        '/oauth/authorize', 
        array(
            'data' => $data, 
            'method' => 'post'
        )
    );
debug($result);
Rob Sawyer
  • 2,163
  • 1
  • 24
  • 25
  • Mock the `getAuthorizeParams()` function to return the values you want. – Derek Jul 29 '13 at 00:13
  • Also there's a bug in CakePHP 2 that doesn't properly use the Security component in unit tests. Make sure you're using 2.3.6 or higher. – Derek Jul 29 '13 at 00:15
  • Yeah, I was thinking the same, but I tried to mock getAuthorizeParams(), but I'm still getting {"error":"invalid_client","error_description":"No client id supplied"}. Thanks for the Security tip, I've upgraded to version 2.3.8. – Rob Sawyer Jul 29 '13 at 07:30
  • The functions inside OAuth that you want to mock are an array of strings with the 'methods' key, ie: `$this->generate('OAuth', array('methods' => array('getAuthorizeParams'), 'components' => array(...));` – Derek Jul 29 '13 at 13:42

1 Answers1

0

Mock the getAuthorizeParams() function to return the values you want.

The functions inside OAuth that you want to mock are an array of strings with the 'methods' key, ie:

$this->generate(
    'OAuth', 
    array(
        'methods' => array(
            'getAuthorizeParams'
        ),
        'components' => array(
            ...
        )
    )
);

Then before you call your testAction() method:

$this->OAuth->expects($this->once())
    ->method('getAuthorizeParams')
    ->will($this->returnValue($YOUR_EXPECTED_VALUE));
Derek
  • 4,575
  • 3
  • 22
  • 36
  • Still no luck with this. :( – Rob Sawyer Jul 30 '13 at 07:03
  • what exactly is it doing wrong/what's the unexpected behavior? any error messages? are you sure that function will get called with the data you're passing along? – Derek Jul 30 '13 at 15:55
  • The error is `{"error":"invalid_client","error_description":"No client id supplied"}`. The login and authorize work fine when using through the browser. Note: Here's the OAuth code for reference. I had to customize it a bit to get it to work with Threescale. Basically Threescale is handling all of the keys and I'm just putting them in the local db when they get validated. Probably a bit more than you needed to know, but owell. Thanks again for the help. https://github.com/robksawyer/cakephp-oauth-server/blob/master/Controller/OAuthController.php – Rob Sawyer Jul 30 '13 at 23:04