You are here

public function JwtPathAuthTest::testPathAdmin in JSON Web Token Authentication (JWT) 8

Test admin form updates and actual path auth.

File

tests/src/Functional/JwtPathAuthTest.php, line 83

Class

JwtPathAuthTest
Tests path-based authentication.

Namespace

Drupal\Tests\jwt\Functional

Code

public function testPathAdmin() {
  $this
    ->drupalLogin($this->adminUser);
  $url = Url::fromRoute('jwt_path_auth.config_form');
  $this
    ->drupalGet($url);
  $edit = [
    'allowed_path_prefixes' => "/system/files/\nzzz",
  ];
  $this
    ->drupalPostForm(NULL, $edit, 'Save configuration');
  $this
    ->assertText('Paths must start with a slash.');
  $edit = [
    'allowed_path_prefixes' => "/system/files/\r\n/foo/zzz/ \r\n/entity/file/",
  ];
  $this
    ->drupalPostForm(NULL, $edit, 'Save configuration');
  $config = $this
    ->config('jwt_path_auth.config');
  $expected = [
    '/system/files/',
    '/foo/zzz/',
    '/entity/file/',
  ];
  $this
    ->assertSame($expected, $config
    ->get('allowed_path_prefixes'));

  /** @var \Drupal\Core\File\FileSystemInterface $file_system */
  $file_system = $this->container
    ->get('file_system');

  // A temporary private file can be access by the creator.
  // @see file_file_download().
  $file = $this
    ->createPrivateFile('drupal.txt', $this->adminUser
    ->id(), 0);

  // Make sure the logged-in user can access the file.
  $file_real_path = $file_system
    ->realpath($file
    ->getFileUri());
  $this
    ->assertFileExists($file_real_path);
  $this
    ->drupalGet($file
    ->createFileUrl());
  $this
    ->assertResponse(200);
  $this
    ->assertText($this
    ->getFileContent($file));

  // Make sure the logged-in user can access the REST resource. The path
  // should be '/entity/file/' . $file->id().
  $options = [
    'query' => [
      '_format' => 'json',
    ],
  ];
  $file_rest_url = Url::fromRoute('rest.entity.file.GET', [
    'file' => $file
      ->id(),
  ], $options);
  $this
    ->drupalGet($file_rest_url);
  $this
    ->assertResponse(200);
  $this
    ->drupalLogout();

  // Expect a 403 when not authenticated.
  $this
    ->drupalGet($file
    ->createFileUrl());
  $this
    ->assertResponse(403);

  // When Drupal is in a subdirectory (such as drupal.org testbot) any
  // path in the JWT other than a "/" must bre prefixed with the base
  // path - the system does not expect the client to know where Drupal
  // is actually installed in terms of path hierarchy.
  $base_url = $this->container
    ->get('router.request_context')
    ->getBaseUrl();

  /** @var \Drupal\jwt\Transcoder\JwtTranscoderInterface $transcoder */
  $transcoder = $this->container
    ->get('jwt.transcoder');
  $jwt = new JsonWebToken();
  $jwt
    ->setClaim([
    'drupal',
    'path_auth',
    'uid',
  ], $this->adminUser
    ->id());
  $jwt
    ->setClaim([
    'drupal',
    'path_auth',
    'path',
  ], '/');
  $token = $transcoder
    ->encode($jwt);
  $this
    ->assertSame('private://drupal.txt', $file
    ->getFileUri());
  $options = [
    'query' => [
      'jwt' => $token,
    ],
  ];

  // Make a real request with the token in the query string.
  $this
    ->drupalGet($file
    ->createFileUrl(), $options);
  $this
    ->assertResponse(200);
  $this
    ->assertText($this
    ->getFileContent($file));

  // If the path claim on the JWT doesn't match, access should be denied.
  $jwt = new JsonWebToken();
  $jwt
    ->setClaim([
    'drupal',
    'path_auth',
    'uid',
  ], $this->adminUser
    ->id());
  $jwt
    ->setClaim([
    'drupal',
    'path_auth',
    'path',
  ], $base_url . '/foo/');
  $token = $transcoder
    ->encode($jwt);
  $options = [
    'query' => [
      'jwt' => $token,
    ],
  ];
  $this
    ->drupalGet($file
    ->createFileUrl(), $options);
  $this
    ->assertResponse(403);

  // Making a REST api request with no JWT should be denied.
  $options = [
    'query' => [
      '_format' => 'json',
    ],
  ];
  $file_rest_url = Url::fromRoute('rest.entity.file.GET', [
    'file' => $file
      ->id(),
  ], $options);
  $this
    ->drupalGet($file_rest_url);
  $this
    ->assertResponse(403);

  // Token path does not match, should still be 403.
  $options = [
    'query' => [
      '_format' => 'json',
      'jwt' => $token,
    ],
  ];
  $file_rest_url = Url::fromRoute('rest.entity.file.GET', [
    'file' => $file
      ->id(),
  ], $options);
  $this
    ->drupalGet($file_rest_url);
  $this
    ->assertResponse(403);

  // Create a new token matching the request path prefix.
  $jwt = new JsonWebToken();
  $jwt
    ->setClaim([
    'drupal',
    'path_auth',
    'uid',
  ], $this->adminUser
    ->id());
  $jwt
    ->setClaim([
    'drupal',
    'path_auth',
    'path',
  ], $base_url . '/entity/');
  $token = $transcoder
    ->encode($jwt);
  $options = [
    'query' => [
      '_format' => 'json',
      'jwt' => $token,
    ],
  ];
  $file_rest_url = Url::fromRoute('rest.entity.file.GET', [
    'file' => $file
      ->id(),
  ], $options);
  $this
    ->drupalGet($file_rest_url);
  $this
    ->assertResponse(200);
  $json = $this
    ->getSession()
    ->getPage()
    ->getContent();
  $data = json_decode($json, TRUE);
  $this
    ->assertEquals($file
    ->uuid(), $data['uuid'][0]['value']);

  // If the user is blocked, the JWT should stop working.
  $this->adminUser
    ->block();
  $this->adminUser
    ->save();
  $this
    ->drupalGet($file_rest_url);
  $this
    ->assertResponse(403);
}