diff --git a/core/modules/file/src/FileAccessControlHandler.php b/core/modules/file/src/FileAccessControlHandler.php index c0d5145fe8..f4bda3cb7d 100644 --- a/core/modules/file/src/FileAccessControlHandler.php +++ b/core/modules/file/src/FileAccessControlHandler.php @@ -59,11 +59,10 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter if ($operation == 'delete' || $operation == 'update') { $account = $this->prepareUser($account); - $file_uid = $entity->get('uid')->target_id; - // Only admins or the file owner can delete and update the file entity. - // @todo Create a new permission to handle this? - if ($account->hasPermission('administer nodes') || ($account->id() == $file_uid)) { - return AccessResult::allowed()->cachePerPermissions(); + $file_uid = $entity->get('uid')->getValue(); + // Only the file owner can delete and update the file entity. + if ($account->id() == $file_uid[0]['target_id']) { + return AccessResult::allowed(); } return AccessResult::forbidden(); } @@ -124,6 +123,8 @@ protected function checkCreateAccess(AccountInterface $account, array $context, // create file entities that are referenced from another entity // (e.g. an image for a article). A contributed module is free to alter // this to allow file entities to be created directly. + // @todo Update comment to mention REST module when + // https://www.drupal.org/node/1927648 is fixed. return AccessResult::neutral(); } diff --git a/core/modules/rest/tests/src/Unit/EventSubscriber/ResourceResponseSubscriberTest.php b/core/modules/rest/tests/src/Unit/EventSubscriber/ResourceResponseSubscriberTest.php index 7ac71d3b67..eab2d9f89b 100644 --- a/core/modules/rest/tests/src/Unit/EventSubscriber/ResourceResponseSubscriberTest.php +++ b/core/modules/rest/tests/src/Unit/EventSubscriber/ResourceResponseSubscriberTest.php @@ -78,7 +78,7 @@ public function providerTestSerialization() { * * @dataProvider providerTestResponseFormat */ - public function testResponseFormat($methods, array $supported_formats, $request_format, array $request_headers, $request_body, $expected_response_format, $expected_response_content_type, $expected_response_content, array $supported_request_formats = []) { + public function testResponseFormat($methods, array $supported_response_formats, array $supported_request_formats, $request_format, array $request_headers, $request_body, $expected_response_format, $expected_response_content_type, $expected_response_content) { foreach ($request_headers as $key => $value) { unset($request_headers[$key]); $key = strtoupper(str_replace('-', '_', $key)); @@ -93,7 +93,7 @@ public function testResponseFormat($methods, array $supported_formats, $request_ $request->setRequestFormat($request_format); } - $route_requirements = $this->generateRouteRequirements($request, $supported_formats, $supported_request_formats); + $route_requirements = $this->generateRouteRequirements($supported_response_formats, $supported_request_formats); $route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => $this->randomMachineName()], $route_requirements)); @@ -115,7 +115,7 @@ public function testResponseFormat($methods, array $supported_formats, $request_ * * @dataProvider providerTestResponseFormat */ - public function testOnResponseWithCacheableResponse($methods, array $supported_formats, $request_format, array $request_headers, $request_body, $expected_response_format, $expected_response_content_type, $expected_response_content, array $supported_request_formats = []) { + public function testOnResponseWithCacheableResponse($methods, array $supported_response_formats, array $supported_request_formats, $request_format, array $request_headers, $request_body, $expected_response_format, $expected_response_content_type, $expected_response_content) { foreach ($request_headers as $key => $value) { unset($request_headers[$key]); $key = strtoupper(str_replace('-', '_', $key)); @@ -130,7 +130,7 @@ public function testOnResponseWithCacheableResponse($methods, array $supported_f $request->setRequestFormat($request_format); } - $route_requirements = $this->generateRouteRequirements($request, $supported_formats, $supported_request_formats); + $route_requirements = $this->generateRouteRequirements($supported_response_formats, $supported_request_formats); $route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => $this->randomMachineName()], $route_requirements)); @@ -165,7 +165,7 @@ public function testOnResponseWithCacheableResponse($methods, array $supported_f * * @dataProvider providerTestResponseFormat */ - public function testOnResponseWithUncacheableResponse($methods, array $supported_formats, $request_format, array $request_headers, $request_body, $expected_response_format, $expected_response_content_type, $expected_response_content, array $supported_request_formats = []) { + public function testOnResponseWithUncacheableResponse($methods, array $supported_response_formats, array $supported_request_formats, $request_format, array $request_headers, $request_body, $expected_response_format, $expected_response_content_type, $expected_response_content) { foreach ($request_headers as $key => $value) { unset($request_headers[$key]); $key = strtoupper(str_replace('-', '_', $key)); @@ -180,7 +180,7 @@ public function testOnResponseWithUncacheableResponse($methods, array $supported $request->setRequestFormat($request_format); } - $route_requirements = $this->generateRouteRequirements($request, $supported_formats, $supported_request_formats); + $route_requirements = $this->generateRouteRequirements($supported_response_formats, $supported_request_formats); $route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => $this->randomMachineName()], $route_requirements)); @@ -227,6 +227,7 @@ public function providerTestResponseFormat() { // @todo add 'HEAD' in https://www.drupal.org/node/2752325 ['GET'], ['xml', 'json'], + [], 'json', [], NULL, @@ -238,6 +239,7 @@ public function providerTestResponseFormat() { // @todo add 'HEAD' in https://www.drupal.org/node/2752325 ['GET'], ['xml', 'json'], + [], 'xml', [], NULL, @@ -249,6 +251,7 @@ public function providerTestResponseFormat() { // @todo add 'HEAD' in https://www.drupal.org/node/2752325 ['GET'], ['json', 'xml'], + [], FALSE, [], NULL, @@ -260,6 +263,7 @@ public function providerTestResponseFormat() { // @todo add 'HEAD' in https://www.drupal.org/node/2752325 ['GET'], ['xml', 'json'], + [], FALSE, [], NULL, @@ -273,6 +277,7 @@ public function providerTestResponseFormat() { 'unsafe methods with response (POST, PATCH): client requested no format, response should use request body format (JSON)' => [ ['POST', 'PATCH'], ['xml', 'json'], + ['xml', 'json'], FALSE, ['Content-Type' => 'application/json'], $json_encoded, @@ -283,6 +288,7 @@ public function providerTestResponseFormat() { 'unsafe methods with response (POST, PATCH): client requested no format, response should use request body format (XML)' => [ ['POST', 'PATCH'], ['xml', 'json'], + ['xml', 'json'], FALSE, ['Content-Type' => 'text/xml'], $xml_encoded, @@ -293,6 +299,7 @@ public function providerTestResponseFormat() { 'unsafe methods with response (POST, PATCH): client requested format other than request body format (JSON): response format should use requested format (XML)' => [ ['POST', 'PATCH'], ['xml', 'json'], + ['xml', 'json'], 'xml', ['Content-Type' => 'application/json'], $json_encoded, @@ -303,6 +310,7 @@ public function providerTestResponseFormat() { 'unsafe methods with response (POST, PATCH): client requested format other than request body format (XML), but is allowed for the request body (JSON)' => [ ['POST', 'PATCH'], ['xml', 'json'], + ['xml', 'json'], 'json', ['Content-Type' => 'text/xml'], $xml_encoded, @@ -313,20 +321,32 @@ public function providerTestResponseFormat() { 'unsafe methods with response (POST, PATCH): client requested format other than request body format when only XML is allowed as a content type format' => [ ['POST', 'PATCH'], ['xml'], + ['json'], 'json', ['Content-Type' => 'text/xml'], $xml_encoded, 'json', 'application/json', $json_encoded, + ], + 'unsafe methods with response (POST, PATCH): client requested format other than request body format when only JSON is allowed as a content type format' => [ + ['POST', 'PATCH'], ['json'], + ['xml'], + 'xml', + ['Content-Type' => 'application/json'], + $json_encoded, + 'xml', + 'text/xml', + $xml_encoded, ], ]; $unsafe_method_bodyless_test_cases = [ - 'unsafe methods with response bodies (DELETE): client requested no format, response should have no format' => [ + 'unsafe methods without response bodies (DELETE): client requested no format, response should have no format' => [ ['DELETE'], ['xml', 'json'], + ['xml', 'json'], FALSE, ['Content-Type' => 'application/json'], NULL, @@ -334,9 +354,10 @@ public function providerTestResponseFormat() { NULL, '', ], - 'unsafe methods with response bodies (DELETE): client requested format (XML), response should have no format' => [ + 'unsafe methods without response bodies (DELETE): client requested format (XML), response should have no format' => [ ['DELETE'], ['xml', 'json'], + ['xml', 'json'], 'xml', ['Content-Type' => 'application/json'], NULL, @@ -344,9 +365,10 @@ public function providerTestResponseFormat() { NULL, '', ], - 'unsafe methods with response bodies (DELETE): client requested format (JSON), response should have no format' => [ + 'unsafe methods without response bodies (DELETE): client requested format (JSON), response should have no format' => [ ['DELETE'], ['xml', 'json'], + ['xml', 'json'], 'json', ['Content-Type' => 'application/json'], NULL, @@ -384,34 +406,20 @@ protected function getFunctioningResourceResponseSubscriber(RouteMatchInterface /** * Generates route requirements based on supported formats. * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request object. - * @param array $supported_formats - * The supported formats to generate requirements for. + * @param array $supported_response_formats + * The supported response formats to add to the route requirements. + * @param array $supported_request_formats + * The supported request formats to add to the route requirements. * * @return array * An array of route requirements. */ - protected function generateRouteRequirements(Request $request, array $supported_formats, array $supported_request_formats = []) { - // Add the supported formats as allowed response formats so requests can - // receive responses in a different format. - $supported_format_string = implode('|', $supported_formats); - - // If there are supported request formats, use those. Otherwise, use the - // supported formats. - if ($supported_request_formats) { - $request_format_string = implode('|', $supported_request_formats); - } - else { - $request_format_string = $supported_format_string; - } - + protected function generateRouteRequirements(array $supported_response_formats, array $supported_request_formats) { $route_requirements = [ - '_format' => $request_format_string, + '_format' => implode('|', $supported_response_formats), ]; - - if (!$request->isMethodCacheable()) { - $route_requirements['_content_type_format'] = $supported_format_string; + if (!empty($supported_request_formats)) { + $route_requirements['_content_type_format'] = implode('|', $supported_request_formats); } return $route_requirements;