Commit 43a4ef25 authored by alexpott's avatar alexpott

Issue #2065193 by juampy, klausi: Supported_formats and supported_auth should work in the same way.

parent e048d17b
# Enable all methods on nodes. # Enable all methods on nodes.
# You must enable Hal and Basic_auth modules for this to work. Also, if you are
# going to use Basic_auth in a production environment then you should consider
# setting up SSL.
# There are alternatives to Basic_auth in contrib such as OAuth module.
resources: resources:
entity:node: entity:node:
GET: { } GET:
POST: { } supported_formats:
PATCH: { } - hal_json
DELETE: { } supported_auth:
- basic_auth
POST:
supported_formats:
- hal_json
supported_auth:
- basic_auth
PATCH:
supported_formats:
- hal_json
supported_auth:
- basic_auth
DELETE:
supported_formats:
- hal_json
supported_auth:
- basic_auth
# To enable only specific formats for an operation, list the supported_formats. # Multiple formats and multiple authentication providers can be defined for a
# For example, the following config makes JSON the only format available for # resource:
# node GET requests.
# resources:
# entity:node:
# GET:
# supported_formats:
# - json
# #
# To enable only specific authentication methods for an operation, list them # resources:
# at supported_auth. # entity:node:
# For example, the following config only allows Basic HTTP authenticated # GET:
# requests for the POST method on the node entity. # supported_formats:
# resources: # - json
# entity:node: # - hal_json
# POST: # - xml
# supported_auth: # supported_auth:
# - basic_auth # - cookie
# - basic_auth
#
# hal_json is the only format supported for POST and PATCH methods.
#
# The full documentation is located at
# https://drupal.org/documentation/modules/rest
...@@ -60,23 +60,29 @@ protected function routes(RouteCollection $collection) { ...@@ -60,23 +60,29 @@ protected function routes(RouteCollection $collection) {
if ($method && isset($enabled_methods[$method])) { if ($method && isset($enabled_methods[$method])) {
$route->setRequirement('_access_rest_csrf', 'TRUE'); $route->setRequirement('_access_rest_csrf', 'TRUE');
// If the array of configured format restrictions is empty for a // Check that authentication providers are defined.
// method always add the route. if (empty($enabled_methods[$method]['supported_auth']) || !is_array($enabled_methods[$method]['supported_auth'])) {
if (empty($enabled_methods[$method])) { watchdog('rest', 'At least one authentication provider must be defined for resource @id', array(':id' => $id), WATCHDOG_ERROR);
$collection->add("rest.$name", $route);
continue; continue;
} }
// Check if there are authentication provider restrictions in the
// configuration and apply them to the route. // Check that formats are defined.
if (!empty($enabled_methods[$method]['supported_auth']) && is_array($enabled_methods[$method]['supported_auth'])) { if (empty($enabled_methods[$method]['supported_formats']) || !is_array($enabled_methods[$method]['supported_formats'])) {
$route->setOption('_auth', $enabled_methods[$method]['supported_auth']); watchdog('rest', 'At least one format must be defined for resource @id', array(':id' => $id), WATCHDOG_ERROR);
continue;
} }
// If there is no format requirement or if it matches the
// configuration also add the route. // If the route has a format requirement, then verify that the
// resource has it.
$format_requirement = $route->getRequirement('_format'); $format_requirement = $route->getRequirement('_format');
if (!$format_requirement || empty($enabled_methods[$method]['supported_formats']) || in_array($format_requirement, $enabled_methods[$method]['supported_formats'])) { if ($format_requirement && !in_array($format_requirement, $enabled_methods[$method]['supported_formats'])) {
$collection->add("rest.$name", $route); continue;
} }
// The configuration seems legit at this point, so we set the
// authentication provider and add the route.
$route->setOption('_auth', $enabled_methods[$method]['supported_auth']);
$collection->add("rest.$name", $route);
} }
} }
} }
......
...@@ -36,10 +36,18 @@ abstract class RESTTestBase extends WebTestBase { ...@@ -36,10 +36,18 @@ abstract class RESTTestBase extends WebTestBase {
*/ */
protected $testEntityType = 'entity_test'; protected $testEntityType = 'entity_test';
/**
* The default authentication provider to use for testing REST operations.
*
* @var array
*/
protected $defaultAuth;
protected function setUp() { protected function setUp() {
parent::setUp(); parent::setUp();
$this->defaultFormat = 'hal_json'; $this->defaultFormat = 'hal_json';
$this->defaultMimeType = 'application/hal+json'; $this->defaultMimeType = 'application/hal+json';
$this->defaultAuth = array('cookie');
// Create a test content type for node testing. // Create a test content type for node testing.
$this->drupalCreateContentType(array('name' => 'resttest', 'type' => 'resttest')); $this->drupalCreateContentType(array('name' => 'resttest', 'type' => 'resttest'));
} }
...@@ -205,25 +213,31 @@ protected function entityValues($entity_type) { ...@@ -205,25 +213,31 @@ protected function entityValues($entity_type) {
* @param array $auth * @param array $auth
* (Optional) The list of valid authentication methods. * (Optional) The list of valid authentication methods.
*/ */
protected function enableService($resource_type, $method = 'GET', $format = NULL, $auth = array()) { protected function enableService($resource_type, $method = 'GET', $format = NULL, $auth = NULL) {
// Enable REST API for this entity type. // Enable REST API for this entity type.
$config = \Drupal::config('rest.settings'); $config = \Drupal::config('rest.settings');
$settings = array(); $settings = array();
if ($resource_type) { if ($resource_type) {
if ($format) { if ($format == NULL) {
$settings[$resource_type][$method]['supported_formats'][] = $format; $format = $this->defaultFormat;
} }
else { $settings[$resource_type][$method]['supported_formats'][] = $format;
$settings[$resource_type][$method] = array();
if ($auth == NULL) {
$auth = $this->defaultAuth;
} }
}
if (is_array($auth) && !empty($auth)) {
$settings[$resource_type][$method]['supported_auth'] = $auth; $settings[$resource_type][$method]['supported_auth'] = $auth;
} }
$config->set('resources', $settings); $config->set('resources', $settings);
$config->save(); $config->save();
$this->rebuildCache();
}
/**
* Rebuilds routing caches.
*/
protected function rebuildCache() {
// Rebuild routing cache, so that the REST API paths are available. // Rebuild routing cache, so that the REST API paths are available.
$this->container->get('router.builder')->rebuild(); $this->container->get('router.builder')->rebuild();
// Reset the Simpletest permission cache, so that the new resource // Reset the Simpletest permission cache, so that the new resource
......
<?php
/**
* @file
* Definition of Drupal\rest\test\ResourceTest.
*/
namespace Drupal\rest\Tests;
use Drupal\rest\Tests\RESTTestBase;
/**
* Tests the REST resource structure.
*/
class ResourceTest extends RESTTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('hal', 'rest', 'entity_test');
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'Resource structure',
'description' => 'Tests the structure of a REST resource',
'group' => 'REST',
);
}
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->config = \Drupal::config('rest.settings');
// Create an entity programmatically.
$this->entity = $this->entityCreate('entity_test');
$this->entity->save();
}
/**
* Tests that a resource without formats cannot be enabled.
*/
public function testFormats() {
$settings = array(
'entity:entity_test' => array(
'GET' => array(
'supported_auth' => array(
'basic_auth',
),
),
),
);
// Attempt to enable the resource.
$this->config->set('resources', $settings);
$this->config->save();
$this->rebuildCache();
// Verify that accessing the resource returns 401.
$response = $this->httpRequest('entity/entity_test/' . $this->entity->id(), 'GET', NULL, $this->defaultMimeType);
$this->assertResponse('404', 'HTTP response code is 404 when the resource does not define formats.');
$this->curlClose();
}
/**
* Tests that a resource without authentication cannot be enabled.
*/
public function testAuthentication() {
$settings = array(
'entity:entity_test' => array(
'GET' => array(
'supported_formats' => array(
'hal_json',
),
),
),
);
// Attempt to enable the resource.
$this->config->set('resources', $settings);
$this->config->save();
$this->rebuildCache();
// Verify that accessing the resource returns 401.
$response = $this->httpRequest('entity/entity_test/' . $this->entity->id(), 'GET', NULL, $this->defaultMimeType);
$this->assertResponse('404', 'HTTP response code is 404 when the resource does not define authentication.');
$this->curlClose();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment