diff --git a/core/modules/rest/src/Plugin/rest/resource/UserPasswordResetResource.php b/core/modules/rest/src/Plugin/rest/resource/UserPasswordResetResource.php index 308ab6d..fd13d55 100644 --- a/core/modules/rest/src/Plugin/rest/resource/UserPasswordResetResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/UserPasswordResetResource.php @@ -9,6 +9,7 @@ use Drupal\user\UserStorageInterface; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; /** @@ -68,18 +69,31 @@ public static function create(ContainerInterface $container, array $configuratio } /** + * {@inheritdoc} + */ + public function routes() { + $routes = parent::routes(); + + // Make the langcode optional. + foreach ($routes->all() as $route) { + $route->setDefault('langcode', NULL); + } + return $routes; + } + + /** * Responds to user password reset POST requests. * - * @param string $name - * The username or email address, that should be reset. * @param string|null $langcode - * (optional) Language code to use for the notification, overriding account + * Language code to use for the notification, overriding account * language. + * @param string $name + * The username or email address, that should be reset. * * @return \Drupal\rest\ResourceResponse * The HTTP response. */ - public function post($name, $langcode = NULL) { + public function post($langcode, $name) { $name = trim($name); if (!$account = $this->loadUserByNameOrEmail($name)) { diff --git a/core/modules/rest/src/Tests/RESTTestBase.php b/core/modules/rest/src/Tests/RESTTestBase.php index 0b4a99d..f07afd7 100644 --- a/core/modules/rest/src/Tests/RESTTestBase.php +++ b/core/modules/rest/src/Tests/RESTTestBase.php @@ -76,8 +76,8 @@ protected function setUp() { * @param array $request_headers * Some additional request headers. * - * @return string The content returned from the request. - * The content returned from the request. + * @return string + * The content returned from the request. */ protected function httpRequest($url, $method, $body = NULL, $mime_type = NULL, $request_headers = []) { if (!isset($mime_type)) { @@ -264,7 +264,7 @@ protected function entityValues($entity_type) { protected function enableService($resource_type, $method = 'GET', $format = NULL, $auth = NULL) { // Enable REST API for this entity type. $config = $this->config('rest.settings'); - $settings = array(); + $settings = $config->get('resources') ?: []; if ($resource_type) { if ($format == NULL) { diff --git a/core/modules/rest/src/Tests/UserLoginTest.php b/core/modules/rest/src/Tests/UserLoginTest.php index 763712c..8e6a8f3 100644 --- a/core/modules/rest/src/Tests/UserLoginTest.php +++ b/core/modules/rest/src/Tests/UserLoginTest.php @@ -25,8 +25,8 @@ public function testLogin() { $this->enableService('user_login', 'POST', $format, $auth); $this->enableService('user_login_status', 'GET', $format, $auth); - $this->enableService('user_logout', 'POST'); - $this->enableService('user_password_reset', 'POST'); + $this->enableService('user_logout', 'POST', $format, $auth); + $this->enableService('user_password_reset', 'POST', $format, $auth); $permissions[] = 'restful post user_login'; $account = $this->drupalCreateUser($permissions); @@ -37,6 +37,7 @@ public function testLogin() { Role::load(RoleInterface::ANONYMOUS_ID) ->grantPermission('restful post user_login') ->grantPermission('restful get user_login_status') + ->grantPermission('restful post user_password_reset') ->save(); Role::load(RoleInterface::AUTHENTICATED_ID) @@ -51,6 +52,26 @@ public function testLogin() { $this->assertResponse(200); $this->assertResponseBody('"' . UserLoginStatusResource::LOGGED_OUT . '"'); + + // Flooded. + \Drupal::configFactory()->getEditable('user.flood') + ->set('user_limit', 3) + ->save(); + $flood = \Drupal::flood(); + $flood->register('rest.login_cookie'); + $flood->register('rest.login_cookie'); + $flood->register('rest.login_cookie'); + + $request_body = ['name' => $name, 'pass' => $pass]; + $this->httpRequest('/user/login', 'POST', json_encode($request_body), 'application/json'); + $this->assertResponse(400); + $this->assertResponseBody('{"error":"Blocked."}'); + + // After testing the flood control we can increase the limit. + \Drupal::configFactory()->getEditable('user.flood') + ->set('user_limit', 100) + ->save(); + $request_body = []; $this->httpRequest('/user/login/', 'POST', json_encode($request_body), 'application/json'); $this->assertResponse(400); @@ -67,20 +88,16 @@ public function testLogin() { $this->assertResponseBody('{"error":"Missing credentials.pass."}'); // Blocked. - $account->block(); - $account->save(); - $request_body = ['name' => $name]; + $account + ->block() + ->save(); + $request_body = ['name' => $name, 'pass' => $pass]; $this->httpRequest('/user/login', 'POST', json_encode($request_body), 'application/json'); $this->assertResponse(400); $this->assertResponseBody('{"error":"The user has not been activated or is blocked."}'); - $account->activate(); - $account->save(); - - // Flooded. - $request_body = ['name' => $name]; - $this->httpRequest('/user/login', 'POST', json_encode($request_body), 'application/json'); - $this->assertResponse(400); - $this->assertResponseBody('{"error":"Missing credentials.pass."}'); + $account + ->activate() + ->save(); $request_body = ['name' => $name, 'pass' => 'garbage']; $this->httpRequest('/user/login', 'POST', json_encode($request_body), 'application/json'); @@ -97,7 +114,7 @@ public function testLogin() { $response = json_decode($response); $this->assertEqual($name, $response->current_user->name, "The user name is correct."); - $url = Url::fromRoute('/user/login/status'); + $url = Url::fromRoute('rest.user_login_status.GET.json'); $url->setRouteParameter('_format', 'json'); $this->httpRequest($url, 'GET', NULL, 'application/json'); $this->assertResponse(200); @@ -107,7 +124,7 @@ public function testLogin() { $this->httpRequest('/user/logout', 'POST', json_encode($request_body), 'application/json'); $this->assertResponse(204); - $url = Url::fromRoute('/user/login/status'); + $url = Url::fromRoute('rest.user_login_status.GET.json'); $url->setRouteParameter('_format', 'json'); $this->httpRequest($url, 'GET', NULL, 'application/json'); $this->assertResponse(200); @@ -115,14 +132,12 @@ public function testLogin() { $random_name = $this->randomMachineName(); - $url = Url::fromRoute("/user/password/{$random_name}"); - $url->setRouteParameter('_format', 'json'); + $url = Url::fromRoute('rest.user_password_reset.POST', ['name' => $random_name]); $this->httpRequest($url, 'POST', NULL, 'application/json'); $this->assertResponse(400); $this->assertResponseBody('{"error":"' . new FormattableMarkup('%name is not recognized as a username or an email address.', ['%name' => $random_name]) . '"}'); - $url = Url::fromRoute("/user/password/{$name}"); - $url->setRouteParameter('_format', 'json'); + $url = Url::fromRoute('rest.user_password_reset.POST', ['name' => $name]); $this->httpRequest($url, 'POST', NULL, 'application/json'); $this->assertResponse(200); $this->assertResponseBody('Further instructions have been sent to your email address.');