Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

Commit

Permalink
Merge branch 'feature/72' into develop
Browse files Browse the repository at this point in the history
Close #72
  • Loading branch information
weierophinney committed Mar 30, 2015
2 parents abf451a + 5c04f7a commit 6e082c1
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 47 deletions.
9 changes: 9 additions & 0 deletions config/module.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@
'password' => true,
'refresh_token' => true,
),
/*
* Error reporting style
*
* If true, client errors are returned using the
* application/problem+json content type,
* otherwise in the format described in the oauth2 specification
* (default: true)
*/
'api_problem_error_response' => true,
),
'zf-content-negotiation' => array(
'ZF\OAuth2\Controller\Auth' => array(
Expand Down
119 changes: 75 additions & 44 deletions src/Controller/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ class AuthController extends AbstractActionController
*/
protected $server;

/**
* @var boolean
*/
protected $apiProblemErrorResponse = true;

/**
* Constructor
*
Expand All @@ -33,6 +38,30 @@ public function __construct(OAuth2Server $server)
$this->server = $server;
}

/**
* Should the controller return ApiProblemResponse?
*
* @return bool
*/
public function isApiProblemErrorResponse()
{
return $this->apiProblemErrorResponse;
}

/**
* Indicate whether ApiProblemResponse or oauth2 errors should be returned.
*
* Boolean true indicates ApiProblemResponse should be returned (the
* default), while false indicates oauth2 errors (per the oauth2 spec)
* should be returned.
*
* @param bool $apiProblemErrorResponse
*/
public function setApiProblemErrorResponse($apiProblemErrorResponse)
{
$this->apiProblemErrorResponse = (bool) $apiProblemErrorResponse;
}

/**
* Token Action (/oauth)
*/
Expand All @@ -52,21 +81,11 @@ public function tokenAction()

$oauth2request = $this->getOAuth2Request();
$response = $this->server->handleTokenRequest($oauth2request);

if ($response->isClientError()) {
$parameters = $response->getParameters();
$errorUri = isset($parameters['error_uri']) ? $parameters['error_uri'] : null;
$error = isset($parameters['error']) ? $parameters['error'] : null;
$errorDescription = isset($parameters['error_description']) ? $parameters['error_description'] : null;

return new ApiProblemResponse(
new ApiProblem(
$response->getStatusCode(),
$errorDescription,
$errorUri,
$error
)
);
return $this->getErrorResponse($response);
}

return $this->setHttpResponse($response);
}

Expand All @@ -78,17 +97,9 @@ public function resourceAction()
// Handle a request for an OAuth2.0 Access Token and send the response to the client
if (!$this->server->verifyResourceRequest($this->getOAuth2Request())) {
$response = $this->server->getResponse();
$parameters = $response->getParameters();
$errorUri = isset($parameters['error_uri']) ? $parameters['error_uri'] : null;
return new ApiProblemResponse(
new ApiProblem(
$response->getStatusCode(),
$parameters['error_description'],
$errorUri,
$parameters['error']
)
);
return $this->getApiProblemResponse($response);
}

$httpResponse = $this->getResponse();
$httpResponse->setStatusCode(200);
$httpResponse->getHeaders()->addHeaders(array('Content-type' => 'application/json'));
Expand All @@ -107,17 +118,10 @@ public function authorizeAction()
$response = new OAuth2Response();

// validate the authorize request
if (!$this->server->validateAuthorizeRequest($request, $response)) {
$parameters = $response->getParameters();
$errorUri = isset($parameters['error_uri']) ? $parameters['error_uri'] : null;
return new ApiProblemResponse(
new ApiProblem(
$response->getStatusCode(),
$parameters['error_description'],
$errorUri,
$parameters['error']
)
);
$isValid = $this->server->validateAuthorizeRequest($request, $response);

if (!$isValid) {
return $this->getErrorResponse($response);
}

$authorized = $request->request('authorized', false);
Expand All @@ -141,16 +145,7 @@ public function authorizeAction()
return $this->redirect()->toUrl($redirect);
}

$parameters = $response->getParameters();
$errorUri = isset($parameters['error_uri']) ? $parameters['error_uri'] : null;
return new ApiProblemResponse(
new ApiProblem(
$response->getStatusCode(),
$parameters['error_description'],
$errorUri,
$parameters['error']
)
);
return $this->getErrorResponse($response);
}

/**
Expand All @@ -166,6 +161,42 @@ public function receiveCodeAction()
return $view;
}

/**
* @param OAuth2Response $response
* @return ApiProblemResponse|\Zend\Stdlib\ResponseInterface
*/
protected function getErrorResponse(OAuth2Response $response)
{
if ($this->isApiProblemErrorResponse()) {
return $this->getApiProblemResponse($response);
}

return $this->setHttpResponse($response);
}

/**
* Map OAuth2Response to ApiProblemResponse
*
* @param OAuth2Response $response
* @return ApiProblemResponse
*/
protected function getApiProblemResponse(OAuth2Response $response)
{
$parameters = $response->getParameters();
$errorUri = isset($parameters['error_uri']) ? $parameters['error_uri'] : null;
$error = isset($parameters['error']) ? $parameters['error'] : null;
$errorDescription = isset($parameters['error_description']) ? $parameters['error_description'] : null;

return new ApiProblemResponse(
new ApiProblem(
$response->getStatusCode(),
$errorDescription,
$errorUri,
$error
)
);
}

/**
* Create an OAuth2 request based on the ZF2 request object
*
Expand Down
8 changes: 7 additions & 1 deletion src/Factory/AuthControllerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ class AuthControllerFactory implements FactoryInterface
public function createService(ServiceLocatorInterface $controllers)
{
$services = $controllers->getServiceLocator()->get('ServiceManager');
return new AuthController($services->get('ZF\OAuth2\Service\OAuth2Server'));
$authController = new AuthController($services->get('ZF\OAuth2\Service\OAuth2Server'));

$config = $services->get('Config');
$authController->setApiProblemErrorResponse((isset($config['zf-oauth2']['api_problem_error_response'])
&& $config['zf-oauth2']['api_problem_error_response'] === true));

return $authController;
}
}
80 changes: 78 additions & 2 deletions test/Controller/AuthControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,51 @@ public function testToken()
$this->assertTrue(!empty($response['token_type']));
}

public function testTokenErrorIsApiProblem()
{
$request = $this->getRequest();
$request->getPost()->set('grant_type', 'fake_grant_type');
$request->getServer()->set('PHP_AUTH_USER', 'testclient');
$request->getServer()->set('PHP_AUTH_PW', 'testpass');
$request->setMethod('POST');

$this->dispatch('/oauth');
$this->assertControllerName('ZF\OAuth2\Controller\Auth');
$this->assertActionName('token');
$this->assertResponseStatusCode(400);

$headers = $this->getResponse()->getHeaders();
$this->assertEquals('application/problem+json', $headers->get('content-type')->getFieldValue());

$response = json_decode($this->getResponse()->getContent(), true);
$this->assertEquals('unsupported_grant_type', $response['title']);
$this->assertEquals('Grant type "fake_grant_type" not supported', $response['detail']);
$this->assertEquals('400', $response['status']);
}

public function testTokenErrorIsOAuth2Format()
{
$request = $this->getRequest();
$request->getPost()->set('grant_type', 'fake_grant_type');
$request->getServer()->set('PHP_AUTH_USER', 'testclient');
$request->getServer()->set('PHP_AUTH_PW', 'testpass');
$request->setMethod('POST');

$this->setIsOAuth2FormatResponse();

$this->dispatch('/oauth');
$this->assertControllerName('ZF\OAuth2\Controller\Auth');
$this->assertActionName('token');
$this->assertResponseStatusCode(400);

$headers = $this->getResponse()->getHeaders();
$this->assertEquals('application/json', $headers->get('content-type')->getFieldValue());

$response = json_decode($this->getResponse()->getContent(), true);
$this->assertEquals('unsupported_grant_type', $response['error']);
$this->assertEquals('Grant type "fake_grant_type" not supported', $response['error_description']);
}

public function testAuthorizeForm()
{
$_GET['response_type'] = 'code';
Expand All @@ -59,7 +104,7 @@ public function testAuthorizeForm()
$this->assertXpathQuery('//form/input[@name="authorized" and @value="no"]');
}

public function testAuthorizeErrorParam()
public function testAuthorizeParamErrorIsApiProblem()
{
$this->dispatch('/oauth/authorize');

Expand All @@ -76,6 +121,24 @@ public function testAuthorizeErrorParam()
$this->assertEquals('400', $response['status']);
}

public function testAuthorizeParamErrorIsOAuth2Format()
{
$this->setIsOAuth2FormatResponse();

$this->dispatch('/oauth/authorize');

$this->assertControllerName('ZF\OAuth2\Controller\Auth');
$this->assertActionName('authorize');
$this->assertResponseStatusCode(400);

$headers = $this->getResponse()->getHeaders();
$this->assertEquals('application/json', $headers->get('content-type')->getFieldValue());

$response = json_decode($this->getResponse()->getContent(), true);
$this->assertEquals('invalid_client', $response['error']);
$this->assertEquals('No client id supplied', $response['error_description']);
}

public function testAuthorizeCode()
{
$_GET['response_type'] = 'code';
Expand Down Expand Up @@ -174,11 +237,13 @@ public function testResource()
$this->assertResponseStatusCode(200);

$response = json_decode($this->getResponse()->getContent(), true);

$this->assertTrue($response['success']);
$this->assertEquals('You accessed my APIs!', $response['message']);

// test resource through token by Bearer header
$server->set('HTTP_AUTHORIZATION', "Bearer $token");
$request->getHeaders()
->addHeaderLine('Authorization', 'Bearer ' . $token);
unset($post['access_token']);
$request->setMethod('GET');

Expand All @@ -191,4 +256,15 @@ public function testResource()
$this->assertTrue($response['success']);
$this->assertEquals('You accessed my APIs!', $response['message']);
}

protected function setIsOAuth2FormatResponse()
{
$serviceManager = $this->getApplication()->getServiceManager();

$config = $serviceManager->get('Config');
$config['zf-oauth2']['api_problem_error_response'] = false;

$serviceManager->setAllowOverride(true);
$serviceManager->setService('Config', $config);
}
}
6 changes: 6 additions & 0 deletions test/Factory/AuthControllerFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ protected function setUp()

$this->services = $services = new ServiceManager();

$this->services->setService('Config', array(
'zf-oauth2' => array(
'api_problem_error_response' => true,
),
));

$this->controllers = $controllers = new ControllerManager();
$controllers->setServiceLocator(new ServiceManager());
$controllers->getServiceLocator()->setService('ServiceManager', $services);
Expand Down

0 comments on commit 6e082c1

Please sign in to comment.