diff --git a/core/modules/rest/src/Plugin/ResourceBase.php b/core/modules/rest/src/Plugin/ResourceBase.php index 46f77f6..240461f 100644 --- a/core/modules/rest/src/Plugin/ResourceBase.php +++ b/core/modules/rest/src/Plugin/ResourceBase.php @@ -42,6 +42,11 @@ protected $logger; /** + * @var \Drupal\Core\Config\ImmutableConfig + */ + protected $flood; + + /** * Constructs a Drupal\rest\Plugin\ResourceBase object. * * @param array $configuration @@ -55,10 +60,11 @@ * @param \Psr\Log\LoggerInterface $logger * A logger instance. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, $flood) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->serializerFormats = $serializer_formats; $this->logger = $logger; + $this->flood = $flood; } /** @@ -70,7 +76,9 @@ public static function create(ContainerInterface $container, array $configuratio $plugin_id, $plugin_definition, $container->getParameter('serializer.formats'), - $container->get('logger.factory')->get('rest') + $container->get('logger.factory')->get('rest'), + // FIX ME + \Drupal::flood() ); } @@ -210,4 +218,20 @@ protected function getBaseRoute($canonical_path, $method) { return $route; } + /** + * Checks for flooding. + * + * @param \Drupal\Core\Config\ImmutableConfig $config + * @param $name + * @return bool + */ + protected function restFloodControl($config, $name) { + $limit = $config->get('user_limit'); + $interval = $config->get('user_window'); + if (!\Drupal::flood()->isAllowed($name, $limit, $interval)) { + return TRUE; + } + return FALSE; + } + } diff --git a/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php b/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php new file mode 100644 index 0000000..14dadbf --- /dev/null +++ b/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php @@ -0,0 +1,104 @@ + 'login', 'logout' + * 'credentials' => array( + * 'name' => 'your-name', + * 'pass' => 'your-password', + * ), + * ) + * + * The operation and username + pass for the login op. + * + * @return \Drupal\rest\ResourceResponse + * The HTTP response object. + */ + public function post(array $operation = array()) { + + switch ($operation['op']) { + + case 'login': + if (!empty($operation['credentials'])) { + return $this->login($operation['credentials']); + } + return new ResourceResponse('Missing credentials.', 400, array()); + + case 'logout': + return $this->logout(); + + default: + return new ResourceResponse('Unsupported op.', 400, array()); + + } + } + + /** + * User login. + * + * @param array $credentials + * The username and pass for the user. + * + * @return \Drupal\rest\ResourceResponse + * The HTTP response object + */ + protected function login(array $credentials = array()) { + // Verify that the username is filled. + if (!array_key_exists('name', $credentials)) { + return new ResourceResponse('Missing credentials.name.', 400, array()); + } + // Verify that the username is filled. + if (!array_key_exists('pass', $credentials)) { + return new ResourceResponse('Missing credentials.pass.', 400, array()); + } + + // Flood control. + if ($this->restFloodControl(\Drupal::config('user.flood'), 'rest.login_cookie')) { + return new ResourceResponse('Blocked.', 400, array()); + } + + // Log in the user. + if ($uid = \Drupal::service('user.auth')->authenticate($credentials['name'], $credentials['pass'])) { + $user = User::load($uid); + user_login_finalize($user); + return new ResourceResponse('You are logged in as ' . $credentials['name'], 200, array()); + } + $this->flood->register('rest.login_cookie', \Drupal::config('user.flood')->get('user_window')); + return new ResourceResponse('Sorry, unrecognized username or password.', 400, array()); + } + + /** + * User Logout. + * + * @return ResourceResponse + */ + protected function logout() { + user_logout(); + return new ResourceResponse('Logged out!', 200, array()); + } + +} diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php index 2aa65ad..4fd9fd8 100644 --- a/core/modules/rest/src/RequestHandler.php +++ b/core/modules/rest/src/RequestHandler.php @@ -59,9 +59,15 @@ public function handle(RouteMatchInterface $route_match, Request $request) { $method_settings = $config[$plugin][$request->getMethod()]; if (empty($method_settings['supported_formats']) || in_array($format, $method_settings['supported_formats'])) { $definition = $resource->getPluginDefinition(); - $class = $definition['serialization_class']; + $class = isset($definition['serialization_class']) ? $definition['serialization_class'] : NULL; try { - $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method)); + if ($class) { + $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method)); + } + // Avoid denormalization because we need to instantiate a class. + else { + $unserialized = $serializer->decode($received, $format, array('request_method' => $method)); + } } catch (UnexpectedValueException $e) { $error['error'] = $e->getMessage(); diff --git a/core/modules/rest/src/Tests/RESTTestBase.php b/core/modules/rest/src/Tests/RESTTestBase.php index ff382d5..edddae2 100644 --- a/core/modules/rest/src/Tests/RESTTestBase.php +++ b/core/modules/rest/src/Tests/RESTTestBase.php @@ -77,7 +77,7 @@ protected function setUp() { * @return string * The content returned from the request. */ - protected function httpRequest($url, $method, $body = NULL, $mime_type = NULL) { + protected function httpRequest($url, $method, $body = NULL, $mime_type = NULL, $request_headers = []) { if (!isset($mime_type)) { $mime_type = $this->defaultMimeType; } @@ -107,10 +107,11 @@ protected function httpRequest($url, $method, $body = NULL, $mime_type = NULL) { CURLOPT_POSTFIELDS => $body, CURLOPT_URL => $url, CURLOPT_NOBODY => FALSE, - CURLOPT_HTTPHEADER => array( + CURLOPT_HTTPHEADER => array_merge( + array( 'Content-Type: ' . $mime_type, 'X-CSRF-Token: ' . $token, - ), + ), $request_headers), ); break; @@ -162,6 +163,9 @@ protected function httpRequest($url, $method, $body = NULL, $mime_type = NULL) { $this->verbose($method . ' request to: ' . $url . '