diff --git a/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php b/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php index fa19040..8cb06bf 100644 --- a/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php @@ -2,6 +2,7 @@ namespace Drupal\rest\Plugin\rest\resource; +use Drupal\Core\Access\CsrfTokenGenerator; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Flood\FloodInterface; use Drupal\rest\ResourceResponse; @@ -51,6 +52,13 @@ class UserLoginResource extends ResourceBase { protected $logger; /** + * The Csrf Token Generator. + * + * @var \Drupal\Core\Access\CsrfTokenGenerator + */ + protected $csrfToken; + + /** * Constructs a new UserLoginResource object. * * @param array $configuration @@ -69,13 +77,16 @@ class UserLoginResource extends ResourceBase { * The flood control mechanism. * @param \Drupal\user\UserStorageInterface $user_storage * The user storage. + * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token + * The Csrf Token Generator. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, ConfigFactoryInterface $config_factory, FloodInterface $flood, UserStorageInterface $user_storage) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, ConfigFactoryInterface $config_factory, FloodInterface $flood, UserStorageInterface $user_storage, CsrfTokenGenerator $csrf_token) { parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger, $flood); $this->configFactory = $config_factory; $this->flood = $flood; $this->userStorage = $user_storage; $this->logger = $logger; + $this->csrfToken = $csrf_token; } /** @@ -90,7 +101,8 @@ public static function create(ContainerInterface $container, array $configuratio $container->get('logger.factory')->get('rest'), $container->get('config.factory'), $container->get('flood'), - $container->get('entity.manager')->getStorage('user') + $container->get('entity.manager')->getStorage('user'), + $container->get('csrf_token') ); } @@ -100,17 +112,17 @@ public static function create(ContainerInterface $container, array $configuratio * @return \Drupal\rest\ResourceResponse * The HTTP response object. */ - public function post($name, $password) { - if (empty($credentials)) { + public function post($credentials) { + if (!isset($credentials['name']) && !isset($credentials['pass'])) { throw new BadRequestHttpException('Missing credentials.'); } // Verify that the username is filled. - if (!isset($name)) { + if (!isset($credentials['name'])) { throw new BadRequestHttpException('Missing credentials.name.'); } // Verify that the password is filled. - if (!isset($password)) { + if (!isset($credentials['pass'])) { throw new BadRequestHttpException('Missing credentials.pass.'); } @@ -137,7 +149,7 @@ public function post($name, $password) { 'roles' => $user->getRoles(), 'name' => $user->getAccountName(), ], - 'csrf_token' => \Drupal::csrfToken()->get('rest'), + 'csrf_token' => $this->csrfToken->get('rest'), ]; return new ResourceResponse($response_data, 200, []); diff --git a/core/modules/rest/src/Tests/UserLoginTest.php b/core/modules/rest/src/Tests/UserLoginTest.php index fb40dbc..a28c982 100644 --- a/core/modules/rest/src/Tests/UserLoginTest.php +++ b/core/modules/rest/src/Tests/UserLoginTest.php @@ -2,6 +2,7 @@ namespace Drupal\rest\Tests; +use Drupal\Core\Url; use Drupal\user\Entity\Role; use Drupal\user\RoleInterface; @@ -19,11 +20,22 @@ public function testLogin() { // Enable the service. $config = $this->config('rest.settings'); $settings = []; - $resource = ['type' => 'user_login', 'method' => 'POST']; $format = 'json'; $auth = $this->defaultAuth; + + $resource = ['type' => 'user_login', 'method' => 'POST']; + $settings[$resource['type']][$resource['method']]['supported_formats'][] = $format; + $settings[$resource['type']][$resource['method']]['supported_auth'] = $auth; + + $resource = ['type' => 'user_login_status', 'method' => 'GET']; $settings[$resource['type']][$resource['method']]['supported_formats'][] = $format; $settings[$resource['type']][$resource['method']]['supported_auth'] = $auth; + + $resource = ['type' => 'user_logout', 'method' => 'POST']; + $settings[$resource['type']][$resource['method']]['supported_formats'][] = $format; + $settings[$resource['type']][$resource['method']]['supported_auth'] = $auth; + + $config->set('resources', $settings); $config->save(); @@ -37,84 +49,54 @@ public function testLogin() { // Add login permission to anonymous user. Role::load(RoleInterface::ANONYMOUS_ID) ->grantPermission('restful post user_login') + ->grantPermission('restful get user_login_status') ->save(); - $payload = array(); - $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); - $this->assertResponseBody('400', '{"error":"No op found. Use: status, login, logout."}'); + Role::load(RoleInterface::AUTHENTICATED_ID) + ->grantPermission('restful get user_login_status') + ->grantPermission('restful post user_logout') + ->save(); - $payload = $this->getPayload('garbage'); - $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); - $this->assertResponseBody('400', '{"error":"Unsupported op garbage."}'); - $payload = $this->getPayload('status'); - $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); + $url = URL::fromRoute('rest.user_login_status.GET.json'); + $url->setRouteParameter('_format', 'json'); + $this->httpRequest($url, 'GET', NULL, 'application/json'); $this->assertResponseBody('200', '"You are not logged in."'); - $payload = $this->getPayload('login'); + $payload = []; $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); $this->assertResponseBody('400', '{"error":"Missing credentials."}'); - $payload = $this->getPayload('login', $name); - $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); - $this->assertResponseBody('400', '{"error":"Missing credentials.pass."}'); - - $payload = $this->getPayload('login', NULL, $pass); + $payload = ['pass' => $pass]; $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); $this->assertResponseBody('400', '{"error":"Missing credentials.name."}'); - $payload = $this->getPayload('login', $name, 'garbage'); + $payload = ['name' => $name, 'pass' => 'garbage']; $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); $this->assertResponseBody('400', '{"error":"Sorry, unrecognized username or password."}'); - $payload = $this->getPayload('login', 'garbage', $pass); + $payload = ['name' => 'garbage', 'pass' => $pass]; $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); $this->assertResponseBody('400', '{"error":"Sorry, unrecognized username or password."}'); - $payload = $this->getPayload('login', $name, $pass); + $payload = ['name' => $name, 'pass' => $pass]; $response = $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); $response = json_decode($response); $this->assertEqual($name, $response->current_user->name, "The user name is correct."); - $payload = $this->getPayload('status'); - $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); + $url = Url::fromRoute('rest.user_login_status.GET.json'); + $url->setRouteParameter('_format', 'json'); + $this->httpRequest($url, 'GET', NULL, 'application/json'); $this->assertResponseBody('200', '"You are logged in."'); - $payload = $this->getPayload('logout'); - $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); + $payload = ['name' => $name, 'pass' => $pass]; + $this->httpRequest('user_logout', 'POST', json_encode($payload), 'application/json'); $this->assertResponseBody('200', '"You are logged out."'); - $payload = $this->getPayload('status'); - $this->httpRequest('user_login', 'POST', json_encode($payload), 'application/json'); + $url = Url::fromRoute('rest.user_login_status.GET.json'); + $url->setRouteParameter('_format', 'json'); + $this->httpRequest($url, 'GET', NULL, 'application/json'); $this->assertResponseBody('200', '"You are not logged in."'); - } - /** - * Helper function to build the payload. - * - * @param string $op - * The operation. - * @param string $name - * The user name. - * @param string $pass - * The user pass. - * - * @return array - * The payload. - */ - private function getPayload( $op, $name = NULL, $pass = NULL) { - $result = array('op' => $op); - - if ($op == 'login') { - $result['credentials'] = array(); - if (isset($name)) { - $result['credentials']['name'] = $name; - } - if (isset($pass)) { - $result['credentials']['pass'] = $pass; - } - } - return $result; - } }