540 lines
16 KiB
PHP
Executable File
540 lines
16 KiB
PHP
Executable File
<?php
|
|
|
|
/*
|
|
* This file is part of jwt-auth.
|
|
*
|
|
* (c) Sean Tymon <tymon148@gmail.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Tymon\JWTAuth\Test\Http;
|
|
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Route;
|
|
use Illuminate\Support\Facades\Crypt;
|
|
use Mockery;
|
|
use Tymon\JWTAuth\Contracts\Http\Parser as ParserContract;
|
|
use Tymon\JWTAuth\Http\Parser\AuthHeaders;
|
|
use Tymon\JWTAuth\Http\Parser\Cookies;
|
|
use Tymon\JWTAuth\Http\Parser\InputSource;
|
|
use Tymon\JWTAuth\Http\Parser\LumenRouteParams;
|
|
use Tymon\JWTAuth\Http\Parser\Parser;
|
|
use Tymon\JWTAuth\Http\Parser\QueryString;
|
|
use Tymon\JWTAuth\Http\Parser\RouteParams;
|
|
use Tymon\JWTAuth\Test\AbstractTestCase;
|
|
|
|
class ParserTest extends AbstractTestCase
|
|
{
|
|
/** @test */
|
|
public function it_should_return_the_token_from_the_authorization_header()
|
|
{
|
|
$request = Request::create('foo', 'POST');
|
|
$request->headers->set('Authorization', 'Bearer foobar');
|
|
|
|
$parser = new Parser($request);
|
|
|
|
$parser->setChain([
|
|
new QueryString,
|
|
new InputSource,
|
|
new AuthHeaders,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_the_prefixed_authentication_header()
|
|
{
|
|
$request = Request::create('foo', 'POST');
|
|
$request->headers->set('Authorization', 'Custom foobar');
|
|
|
|
$parser = new Parser($request);
|
|
|
|
$parser->setChain([
|
|
new QueryString,
|
|
new InputSource,
|
|
(new AuthHeaders)->setHeaderPrefix('Custom'),
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_the_custom_authentication_header()
|
|
{
|
|
$request = Request::create('foo', 'POST');
|
|
$request->headers->set('custom_authorization', 'Bearer foobar');
|
|
|
|
$parser = new Parser($request);
|
|
|
|
$parser->setChain([
|
|
new QueryString,
|
|
new InputSource,
|
|
(new AuthHeaders)->setHeaderName('custom_authorization'),
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_the_alt_authorization_headers()
|
|
{
|
|
$request1 = Request::create('foo', 'POST');
|
|
$request1->server->set('HTTP_AUTHORIZATION', 'Bearer foobar');
|
|
|
|
$request2 = Request::create('foo', 'POST');
|
|
$request2->server->set('REDIRECT_HTTP_AUTHORIZATION', 'Bearer foobarbaz');
|
|
|
|
$parser = new Parser($request1, [
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
|
|
$parser->setRequest($request2);
|
|
$this->assertSame($parser->parseToken(), 'foobarbaz');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_ignore_non_bearer_tokens()
|
|
{
|
|
$request = Request::create('foo', 'POST');
|
|
$request->headers->set('Authorization', 'Basic OnBhc3N3b3Jk');
|
|
|
|
$parser = new Parser($request);
|
|
|
|
$parser->setChain([
|
|
new QueryString,
|
|
new InputSource,
|
|
new AuthHeaders,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertNull($parser->parseToken());
|
|
$this->assertFalse($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_not_strip_trailing_hyphens_from_the_authorization_header()
|
|
{
|
|
$request = Request::create('foo', 'POST');
|
|
$request->headers->set('Authorization', 'Bearer foobar--');
|
|
|
|
$parser = new Parser($request);
|
|
|
|
$parser->setChain([
|
|
new QueryString,
|
|
new InputSource,
|
|
new AuthHeaders,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar--');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/**
|
|
* @test
|
|
* @dataProvider whitespaceProvider
|
|
*/
|
|
public function it_should_handle_excess_whitespace_from_the_authorization_header($whitespace)
|
|
{
|
|
$request = Request::create('foo', 'POST');
|
|
$request->headers->set('Authorization', "Bearer{$whitespace}foobar{$whitespace}");
|
|
|
|
$parser = new Parser($request);
|
|
|
|
$parser->setChain([
|
|
new QueryString,
|
|
new InputSource,
|
|
new AuthHeaders,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
public function whitespaceProvider()
|
|
{
|
|
return [
|
|
'space' => [' '],
|
|
'multiple spaces' => [' '],
|
|
'tab' => ["\t"],
|
|
'multiple tabs' => ["\t\t\t"],
|
|
'new line' => ["\n"],
|
|
'multiple new lines' => ["\n\n\n"],
|
|
'carriage return' => ["\r"],
|
|
'carriage returns' => ["\r\r\r"],
|
|
'mixture of whitespace' => ["\t \n \r \t \n"],
|
|
];
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_query_string()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['token' => 'foobar']);
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_the_custom_query_string()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['custom_token_key' => 'foobar']);
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
(new QueryString)->setKey('custom_token_key'),
|
|
new InputSource,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_the_query_string_not_the_input_source()
|
|
{
|
|
$request = Request::create('foo?token=foobar', 'POST', [], [], [], [], json_encode(['token' => 'foobarbaz']));
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_the_custom_query_string_not_the_custom_input_source()
|
|
{
|
|
$request = Request::create('foo?custom_token_key=foobar', 'POST', [], [], [], [], json_encode(['custom_token_key' => 'foobarbaz']));
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
(new QueryString)->setKey('custom_token_key'),
|
|
(new InputSource)->setKey('custom_token_key'),
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_input_source()
|
|
{
|
|
$request = Request::create('foo', 'POST', [], [], [], [], json_encode(['token' => 'foobar']));
|
|
$request->headers->set('Content-Type', 'application/json');
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_the_custom_input_source()
|
|
{
|
|
$request = Request::create('foo', 'POST', [], [], [], [], json_encode(['custom_token_key' => 'foobar']));
|
|
$request->headers->set('Content-Type', 'application/json');
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
(new InputSource)->setKey('custom_token_key'),
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_an_unencrypted_cookie()
|
|
{
|
|
$request = Request::create('foo', 'POST', [], ['token' => 'foobar']);
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
new Cookies(false),
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_a_crypted_cookie()
|
|
{
|
|
Crypt::shouldReceive('encrypt')
|
|
->with('foobar')
|
|
->once()
|
|
->andReturn('cryptedFoobar');
|
|
|
|
$request = Request::create('foo', 'POST', [], ['token' => Crypt::encrypt('foobar')]);
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
new Cookies(true),
|
|
]);
|
|
|
|
Crypt::shouldReceive('decrypt')
|
|
->with('cryptedFoobar')
|
|
->times(2)
|
|
->andReturn('foobar');
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_route()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['foo' => 'bar']);
|
|
$request->setRouteResolver(function () {
|
|
return $this->getRouteMock('foobar');
|
|
});
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_the_token_from_route_with_a_custom_param()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['foo' => 'bar']);
|
|
$request->setRouteResolver(function () {
|
|
return $this->getRouteMock('foobar', 'custom_route_param');
|
|
});
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
(new RouteParams)->setKey('custom_route_param'),
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_ignore_routeless_requests()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['foo' => 'bar']);
|
|
$request->setRouteResolver(function () {
|
|
//
|
|
});
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertNull($parser->parseToken());
|
|
$this->assertFalse($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_ignore_lumen_request_arrays()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['foo' => 'bar']);
|
|
$request->setRouteResolver(function () {
|
|
return [false, ['uses' => 'someController'], ['token' => 'foobar']];
|
|
});
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertNull($parser->parseToken());
|
|
$this->assertFalse($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_accept_lumen_request_arrays_with_special_class()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['foo' => 'bar']);
|
|
$request->setRouteResolver(function () {
|
|
return [false, ['uses' => 'someController'], ['token' => 'foo.bar.baz']];
|
|
});
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new LumenRouteParams,
|
|
]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foo.bar.baz');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_return_null_if_no_token_in_request()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['foo' => 'bar']);
|
|
$request->setRouteResolver(function () {
|
|
return $this->getRouteMock();
|
|
});
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChain([
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
]);
|
|
|
|
$this->assertNull($parser->parseToken());
|
|
$this->assertFalse($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_retrieve_the_chain()
|
|
{
|
|
$chain = [
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
];
|
|
|
|
$parser = new Parser(Mockery::mock(Request::class));
|
|
$parser->setChain($chain);
|
|
|
|
$this->assertSame($parser->getChain(), $chain);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_retrieve_the_chain_with_alias()
|
|
{
|
|
$chain = [
|
|
new AuthHeaders,
|
|
new QueryString,
|
|
new InputSource,
|
|
new RouteParams,
|
|
];
|
|
|
|
/* @var \Illuminate\Http\Request $request */
|
|
$request = Mockery::mock(Request::class);
|
|
|
|
$parser = new Parser($request);
|
|
$parser->setChainOrder($chain);
|
|
|
|
$this->assertSame($parser->getChain(), $chain);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_set_the_cookie_key()
|
|
{
|
|
$cookies = (new Cookies)->setKey('test');
|
|
$this->assertInstanceOf(Cookies::class, $cookies);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_add_custom_parser()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['foo' => 'bar']);
|
|
|
|
$customParser = Mockery::mock(ParserContract::class);
|
|
$customParser->shouldReceive('parse')->with($request)->andReturn('foobar');
|
|
|
|
$parser = new Parser($request);
|
|
$parser->addParser($customParser);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
/** @test */
|
|
public function it_should_add_multiple_custom_parser()
|
|
{
|
|
$request = Request::create('foo', 'GET', ['foo' => 'bar']);
|
|
|
|
$customParser1 = Mockery::mock(ParserContract::class);
|
|
$customParser1->shouldReceive('parse')->with($request)->andReturn(false);
|
|
|
|
$customParser2 = Mockery::mock(ParserContract::class);
|
|
$customParser2->shouldReceive('parse')->with($request)->andReturn('foobar');
|
|
|
|
$parser = new Parser($request);
|
|
$parser->addParser([$customParser1, $customParser2]);
|
|
|
|
$this->assertSame($parser->parseToken(), 'foobar');
|
|
$this->assertTrue($parser->hasToken());
|
|
}
|
|
|
|
protected function getRouteMock($expectedParameterValue = null, $expectedParameterName = 'token')
|
|
{
|
|
return Mockery::mock(Route::class)
|
|
->shouldReceive('parameter')
|
|
->with($expectedParameterName)
|
|
->andReturn($expectedParameterValue)
|
|
->getMock();
|
|
}
|
|
}
|