Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / core / modules / rest / tests / src / Functional / EntityResource / User / UserResourceTestBase.php
index 0195ddaeb8174af275fadf40630b2c3c4b72dc78..7974cba7306ec32634618a86246b8b3cba58b936 100644 (file)
@@ -3,12 +3,15 @@
 namespace Drupal\Tests\rest\Functional\EntityResource\User;
 
 use Drupal\Core\Url;
+use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
 use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
 use Drupal\user\Entity\User;
 use GuzzleHttp\RequestOptions;
 
 abstract class UserResourceTestBase extends EntityResourceTestBase {
 
+  use BcTimestampNormalizerUnixTestTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -76,6 +79,17 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
     return $user;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function createAnotherEntity() {
+    /** @var \Drupal\user\UserInterface $user */
+    $user = $this->entity->createDuplicate();
+    $user->setUsername($user->label() . '_dupe');
+    $user->save();
+    return $user;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -98,14 +112,10 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
         ],
       ],
       'created' => [
-        [
-          'value' => 123456789,
-        ],
+        $this->formatExpectedTimestampItemValues(123456789),
       ],
       'changed' => [
-        [
-          'value' => $this->entity->getChangedTime(),
-        ],
+        $this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
       ],
       'default_langcode' => [
         [
@@ -122,7 +132,7 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
     return [
       'name' => [
         [
-          'value' => 'Dramallama ' . $this->randomMachineName(),
+          'value' => 'Dramallama',
         ],
       ],
     ];
@@ -145,7 +155,6 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
     // @todo Remove the array_diff_key() call in https://www.drupal.org/node/2821077.
     $original_normalization = array_diff_key($this->serializer->normalize($user, static::$format), ['created' => TRUE, 'changed' => TRUE, 'name' => TRUE]);
 
-
     // Since this test must be performed by the user that is being modified,
     // we cannot use $this->getUrl().
     $url = $user->toUrl()->setOption('query', ['_format' => static::$format]);
@@ -154,60 +163,49 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
     ];
     $request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
 
-
     // Test case 1: changing email.
     $normalization = $original_normalization;
     $normalization['mail'] = [['value' => 'new-email@example.com']];
     $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
-
     // DX: 422 when changing email without providing the password.
     $response = $this->request('PATCH', $url, $request_options);
-    $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response);
-
+    $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response, FALSE, FALSE, FALSE, FALSE);
 
     $normalization['pass'] = [['existing' => 'wrong']];
     $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
     // DX: 422 when changing email while providing a wrong password.
     $response = $this->request('PATCH', $url, $request_options);
-    $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response);
-
+    $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response, FALSE, FALSE, FALSE, FALSE);
 
     $normalization['pass'] = [['existing' => $this->account->passRaw]];
     $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
-
     // 200 for well-formed request.
     $response = $this->request('PATCH', $url, $request_options);
     $this->assertResourceResponse(200, FALSE, $response);
 
-
     // Test case 2: changing password.
     $normalization = $original_normalization;
     $new_password = $this->randomString();
     $normalization['pass'] = [['value' => $new_password]];
     $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
-
     // DX: 422 when changing password without providing the current password.
     $response = $this->request('PATCH', $url, $request_options);
-    $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\npass: Your current password is missing or incorrect; it's required to change the Password.\n", $response);
-
+    $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\npass: Your current password is missing or incorrect; it's required to change the Password.\n", $response, FALSE, FALSE, FALSE, FALSE);
 
     $normalization['pass'][0]['existing'] = $this->account->pass_raw;
     $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
-
     // 200 for well-formed request.
     $response = $this->request('PATCH', $url, $request_options);
     $this->assertResourceResponse(200, FALSE, $response);
 
-
     // Verify that we can log in with the new password.
     $this->assertRpcLogin($user->getAccountName(), $new_password);
 
-
     // Update password in $this->account, prepare for future requests.
     $this->account->passRaw = $new_password;
     $this->initAuthentication();
@@ -216,21 +214,17 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
     ];
     $request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
 
-
     // Test case 3: changing name.
     $normalization = $original_normalization;
     $normalization['name'] = [['value' => 'Cooler Llama']];
     $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
-
     // DX: 403 when modifying username without required permission.
     $response = $this->request('PATCH', $url, $request_options);
     $this->assertResourceErrorResponse(403, "Access denied on updating field 'name'.", $response);
 
-
     $this->grantPermissionsToTestedRole(['change own username']);
 
-
     // 200 for well-formed request.
     $response = $this->request('PATCH', $url, $request_options);
     $this->assertResourceResponse(200, FALSE, $response);
@@ -260,6 +254,49 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
     $this->assertSame(200, $response->getStatusCode());
   }
 
+  /**
+   * Tests PATCHing security-sensitive base fields to change other users.
+   */
+  public function testPatchSecurityOtherUser() {
+    // The anonymous user is never allowed to modify other users.
+    if (!static::$auth) {
+      $this->markTestSkipped();
+    }
+
+    $this->initAuthentication();
+    $this->provisionEntityResource();
+
+    /** @var \Drupal\user\UserInterface $user */
+    $user = $this->account;
+    $original_normalization = array_diff_key($this->serializer->normalize($user, static::$format), ['changed' => TRUE]);
+
+    // Since this test must be performed by the user that is being modified,
+    // we cannot use $this->getUrl().
+    $url = $user->toUrl()->setOption('query', ['_format' => static::$format]);
+    $request_options = [
+      RequestOptions::HEADERS => ['Content-Type' => static::$mimeType],
+    ];
+    $request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
+
+    $normalization = $original_normalization;
+    $normalization['mail'] = [['value' => 'new-email@example.com']];
+    $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
+
+    // Try changing user 1's email.
+    $user1 = [
+      'mail' => [['value' => 'another_email_address@example.com']],
+      'uid' => [['value' => 1]],
+      'name' => [['value' => 'another_user_name']],
+      'pass' => [['existing' => $this->account->passRaw]],
+      'uuid' => [['value' => '2e9403a4-d8af-4096-a116-624710140be0']],
+    ] + $original_normalization;
+    $request_options[RequestOptions::BODY] = $this->serializer->encode($user1, static::$format);
+    $response = $this->request('PATCH', $url, $request_options);
+    // Ensure the email address has not changed.
+    $this->assertEquals('admin@example.com', $this->entityStorage->loadUnchanged(1)->getEmail());
+    $this->assertResourceErrorResponse(403, "Access denied on updating field 'uid'.", $response);
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -280,4 +317,13 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getExpectedUnauthorizedAccessCacheability() {
+    // @see \Drupal\user\UserAccessControlHandler::checkAccess()
+    return parent::getExpectedUnauthorizedAccessCacheability()
+      ->addCacheTags(['user:3']);
+  }
+
 }