Skip to content

Commit

Permalink
Add password grant feature tests
Browse files Browse the repository at this point in the history
  • Loading branch information
X-Coder264 committed Feb 9, 2020
1 parent 98456cb commit d5f7cdc
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 4 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ matrix:
allow_failures:
- env: LARAVEL=^7.0

services:
- mysql

before_install:
- phpenv config-rm xdebug.ini || true
- mysql -e 'CREATE DATABASE forge;'

install:
- travis_retry composer require "illuminate/contracts=${LARAVEL}" --dev --prefer-dist --no-interaction --no-suggest
Expand Down
13 changes: 10 additions & 3 deletions database/factories/PassportClientFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@
'name' => $faker->company,
'secret' => Str::random(40),
'redirect' => $faker->url,
'personal_access_client' => 0,
'password_client' => 0,
'revoked' => 0,
'personal_access_client' => false,
'password_client' => false,
'revoked' => false,
];
});

$factory->state(Client::class, 'password_client', function (Faker $faker) {
return [
'personal_access_client' => false,
'password_client' => true,
];
});
4 changes: 4 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>

<php>
<env name="APP_KEY" value="AckfSECXIvnK5r28GVIWUAxmbBSjTsmF"/>
</php>
</phpunit>
189 changes: 189 additions & 0 deletions tests/Feature/AccessTokenControllerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<?php

namespace Laravel\Passport\Tests\Feature;

use Carbon\CarbonImmutable;
use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Database\Eloquent\Factory;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Laravel\Passport\Client;
use Laravel\Passport\ClientRepository;
use Laravel\Passport\HasApiTokens;
use Laravel\Passport\Token;
use Laravel\Passport\TokenRepository;
use Lcobucci\JWT\Parser;

class AccessTokenControllerTest extends PassportTestCase
{
protected function setUp(): void
{
parent::setUp();

Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('email')->unique();
$table->string('password');
$table->dateTime('created_at');
$table->dateTime('updated_at');
});
}

protected function tearDown(): void
{
Schema::dropIfExists('users');

parent::tearDown();
}

protected function getUserClass(): ?string
{
return User::class;
}

public function testGettingAccessTokenWithPasswordGrant()
{
$this->withoutExceptionHandling();

$password = 'foobar123';
$user = new User();
$user->email = '[email protected]';
$user->password = $this->app->make(Hasher::class)->make($password);
$user->save();

/** @var Client $client */
$client = $this->app->make(Factory::class)->of(Client::class)->state('password_client')->create(['user_id' => $user->id]);

$response = $this->post(
'/oauth/token',
[
'grant_type' => 'password',
'client_id' => $client->id,
'client_secret' => $client->secret,
'username' => $user->email,
'password' => $password,
]
);

$response->assertOk();

$response->assertHeader('pragma', 'no-cache');
$response->assertHeader('cache-control', 'no-store, private');
$response->assertHeader('content-type', 'application/json; charset=UTF-8');

$decodedResponse = $response->decodeResponseJson();

$this->assertArrayHasKey('token_type', $decodedResponse);
$this->assertArrayHasKey('expires_in', $decodedResponse);
$this->assertArrayHasKey('access_token', $decodedResponse);
$this->assertArrayHasKey('refresh_token', $decodedResponse);
$this->assertSame('Bearer', $decodedResponse['token_type']);
$expiresInSeconds = 31622400;
$this->assertEqualsWithDelta($expiresInSeconds, $decodedResponse['expires_in'], 5);

$jwtAccessToken = (new Parser())->parse($decodedResponse['access_token']);
$this->assertTrue($this->app->make(ClientRepository::class)->findActive($jwtAccessToken->getClaim('aud'))->is($client));
$this->assertTrue($this->app->make('auth')->createUserProvider()->retrieveById($jwtAccessToken->getClaim('sub'))->is($user));

$token = $this->app->make(TokenRepository::class)->find($jwtAccessToken->getClaim('jti'));
$this->assertInstanceOf(Token::class, $token);
$this->assertFalse($token->revoked);
$this->assertTrue($token->user->is($user));
$this->assertTrue($token->client->is($client));
$this->assertNull($token->name);
$this->assertLessThanOrEqual(5, CarbonImmutable::now()->addSeconds($expiresInSeconds)->diffInSeconds($token->expires_at));
}

public function testGettingAccessTokenWithPasswordGrantWithInvalidPassword()
{
$password = 'foobar123';
$user = new User();
$user->email = '[email protected]';
$user->password = $this->app->make(Hasher::class)->make($password);
$user->save();

/** @var Client $client */
$client = $this->app->make(Factory::class)->of(Client::class)->state('password_client')->create(['user_id' => $user->id]);

$response = $this->post(
'/oauth/token',
[
'grant_type' => 'password',
'client_id' => $client->id,
'client_secret' => $client->secret,
'username' => $user->email,
'password' => $password.'foo',
]
);

$response->assertStatus(400);

$response->assertHeader('cache-control', 'no-cache, private');
$response->assertHeader('content-type', 'application/json');

$decodedResponse = $response->decodeResponseJson();

$this->assertArrayNotHasKey('token_type', $decodedResponse);
$this->assertArrayNotHasKey('expires_in', $decodedResponse);
$this->assertArrayNotHasKey('access_token', $decodedResponse);
$this->assertArrayNotHasKey('refresh_token', $decodedResponse);

$this->assertArrayHasKey('error', $decodedResponse);
$this->assertSame('invalid_grant', $decodedResponse['error']);
$this->assertArrayHasKey('error_description', $decodedResponse);
$this->assertArrayHasKey('hint', $decodedResponse);
$this->assertArrayHasKey('message', $decodedResponse);

$this->assertSame(0, Token::count());
}

public function testGettingAccessTokenWithPasswordGrantWithInvalidClientSecret()
{
$password = 'foobar123';
$user = new User();
$user->email = '[email protected]';
$user->password = $this->app->make(Hasher::class)->make($password);
$user->save();

/** @var Client $client */
$client = $this->app->make(Factory::class)->of(Client::class)->state('password_client')->create(['user_id' => $user->id]);

$response = $this->post(
'/oauth/token',
[
'grant_type' => 'password',
'client_id' => $client->id,
'client_secret' => $client->secret.'foo',
'username' => $user->email,
'password' => $password,
]
);

$response->assertStatus(401);

$response->assertHeader('cache-control', 'no-cache, private');
$response->assertHeader('content-type', 'application/json');

$decodedResponse = $response->decodeResponseJson();

$this->assertArrayNotHasKey('token_type', $decodedResponse);
$this->assertArrayNotHasKey('expires_in', $decodedResponse);
$this->assertArrayNotHasKey('access_token', $decodedResponse);
$this->assertArrayNotHasKey('refresh_token', $decodedResponse);

$this->assertArrayHasKey('error', $decodedResponse);
$this->assertSame('invalid_client', $decodedResponse['error']);
$this->assertArrayHasKey('error_description', $decodedResponse);
$this->assertSame('Client authentication failed', $decodedResponse['error_description']);
$this->assertArrayNotHasKey('hint', $decodedResponse);
$this->assertArrayHasKey('message', $decodedResponse);
$this->assertSame('Client authentication failed', $decodedResponse['message']);

$this->assertSame(0, Token::count());
}
}

class User extends \Illuminate\Foundation\Auth\User
{
use HasApiTokens;
}
41 changes: 40 additions & 1 deletion tests/Feature/PassportTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,64 @@
namespace Laravel\Passport\Tests\Feature;

use Illuminate\Contracts\Config\Repository;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Laravel\Passport\Passport;
use Laravel\Passport\PassportServiceProvider;
use Orchestra\Testbench\TestCase;

abstract class PassportTestCase extends TestCase
{
use DatabaseTransactions;

protected function setUp(): void
{
parent::setUp();

$this->withFactories(__DIR__.'/../../database/factories');

$this->artisan('migrate:fresh');

Passport::routes();

$this->artisan('passport:keys');
}

protected function getEnvironmentSetUp($app)
{
$app->make(Repository::class)->set('auth.guards.api', ['driver' => 'passport', 'provider' => 'users']);
$config = $app->make(Repository::class);

$config->set('auth.defaults.provider', 'users');

if (null !== ($userClass = $this->getUserClass())) {
$config->set('auth.providers.users.model', $userClass);
}

$config->set('auth.guards.api', ['driver' => 'passport', 'provider' => 'users']);

$config->set('database.default', 'forge');

$config->set('database.connections.forge', [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'username' => 'root',
'password' => '',
'database' => 'forge',
'prefix' => '',
]);
}

protected function getPackageProviders($app)
{
return [PassportServiceProvider::class];
}

/**
* Get the Eloquent user model class name.
*
* @return string|null
*/
protected function getUserClass(): ?string
{
return null;
}
}

0 comments on commit d5f7cdc

Please sign in to comment.