Skip to content

Commit

Permalink
add feature tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hafezdivandari committed Oct 3, 2024
1 parent 2d7efb9 commit f441a47
Show file tree
Hide file tree
Showing 6 changed files with 626 additions and 50 deletions.
123 changes: 120 additions & 3 deletions tests/Feature/AuthorizationCodeGrantTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function testIssueAccessToken()

$response = $this->post('/oauth/authorize', ['auth_token' => $json['authToken']]);
$response->assertRedirect();
$response->assertSessionMissing(['deviceCode', 'authToken']);
$response->assertSessionMissing(['authRequest', 'authToken']);

$location = $response->headers->get('Location');
parse_str(parse_url($location, PHP_URL_QUERY), $params);
Expand Down Expand Up @@ -106,7 +106,7 @@ public function testDenyAuthorization()

$response = $this->delete('/oauth/authorize', ['auth_token' => $json['authToken']]);
$response->assertRedirect();
$response->assertSessionMissing(['deviceCode', 'authToken']);
$response->assertSessionMissing(['authRequest', 'authToken']);

$location = $response->headers->get('Location');
parse_str(parse_url($location, PHP_URL_QUERY), $params);
Expand Down Expand Up @@ -180,6 +180,30 @@ public function testValidateAuthorizationRequest()
$this->assertArrayHasKey('error_description', $json);
}

public function testValidateScopes()
{
$client = ClientFactory::new()->create();

$query = http_build_query([
'client_id' => $client->getKey(),
'redirect_uri' => $redirect = $client->redirect_uris[0],
'response_type' => 'code',
'scope' => 'foo',
'state' => $state = Str::random(40),
]);

$response = $this->get('/oauth/authorize?'.$query);
$response->assertRedirect();

$location = $response->headers->get('Location');
parse_str(parse_url($location, PHP_URL_QUERY), $params);

$this->assertStringStartsWith($redirect.'?', $location);
// $this->assertSame($state, $params['state']);
$this->assertSame('invalid_scope', $params['error']);
$this->assertArrayHasKey('error_description', $params);
}

public function testRedirectGuestUser()
{
Route::get('/foo', fn () => '')->name('login');
Expand Down Expand Up @@ -218,7 +242,100 @@ public function testPromptNone()

$this->assertStringStartsWith($redirect.'?', $location);
$this->assertSame($state, $params['state']);
$this->assertSame('access_denied', $params['error']);
$this->assertSame('consent_required', $params['error']);
$this->assertArrayHasKey('error_description', $params);
}

public function testPromptNoneLoginRequired()
{
$client = ClientFactory::new()->create();

$query = http_build_query([
'client_id' => $client->getKey(),
'redirect_uri' => $redirect = $client->redirect_uris[0],
'response_type' => 'code',
'state' => $state = Str::random(40),
'prompt' => 'none',
]);

$response = $this->get('/oauth/authorize?'.$query);
$response->assertRedirect();

$location = $response->headers->get('Location');
parse_str(parse_url($location, PHP_URL_QUERY), $params);

$this->assertStringStartsWith($redirect.'?', $location);
$this->assertSame($state, $params['state']);
$this->assertSame('login_required', $params['error']);
$this->assertArrayHasKey('error_description', $params);
}

public function testPromptConsent()
{
$client = ClientFactory::new()->create();

$query = http_build_query([
'client_id' => $client->getKey(),
'redirect_uri' => $redirect = $client->redirect_uris[0],
'response_type' => 'code',
'scope' => 'create read update',
'state' => Str::random(40),
]);

$user = UserFactory::new()->create();
$this->actingAs($user, 'web');
$json = $this->get('/oauth/authorize?'.$query)->json();

$response = $this->post('/oauth/authorize', ['auth_token' => $json['authToken']]);
parse_str(parse_url($response->headers->get('Location'), PHP_URL_QUERY), $params);

$this->post('/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' => $client->getKey(),
'client_secret' => $client->plainSecret,
'redirect_uri' => $redirect,
'code' => $params['code'],
]);

$query = http_build_query([
'client_id' => $client->getKey(),
'redirect_uri' => $redirect,
'response_type' => 'code',
'scope' => 'create read',
'state' => Str::random(40),
'prompt' => 'consent',
]);

$response = $this->get('/oauth/authorize?'.$query);

$response->assertOk();
$response->assertSessionHas('authRequest');
$response->assertSessionHas('authToken');
$json = $response->json();
$this->assertEqualsCanonicalizing(['client', 'user', 'scopes', 'request', 'authToken'], array_keys($json));
$this->assertSame(collect(Passport::scopesFor(['create', 'read']))->toArray(), $json['scopes']);
}

public function testPromptLogin()
{
Route::get('/foo', fn () => '')->name('login');

$client = ClientFactory::new()->create();

$query = http_build_query([
'client_id' => $client->getKey(),
'redirect_uri' => $client->redirect_uris[0],
'response_type' => 'code',
'scope' => 'create read update',
'state' => Str::random(40),
'prompt' => 'login',
]);

$user = UserFactory::new()->create();
$this->actingAs($user, 'web');
$response = $this->get('/oauth/authorize?'.$query);

$response->assertSessionHas('promptedForLogin', true);
$response->assertRedirectToRoute('login');
}
}
117 changes: 117 additions & 0 deletions tests/Feature/AuthorizationCodeGrantWithPkceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

namespace Laravel\Passport\Tests\Feature;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
use Laravel\Passport\Database\Factories\ClientFactory;
use Laravel\Passport\Passport;
use Orchestra\Testbench\Concerns\WithLaravelMigrations;
use Workbench\Database\Factories\UserFactory;

class AuthorizationCodeGrantWithPkceTest extends PassportTestCase
{
use WithLaravelMigrations;

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

Passport::tokensCan([
'create' => 'Create',
'read' => 'Read',
'update' => 'Update',
'delete' => 'Delete',
]);

Passport::authorizationView(fn ($params) => $params);
}

public function testIssueAccessToken()
{
$client = ClientFactory::new()->asPublic()->create();

$codeVerifier = Str::random(128);
$codeChallenge = strtr(rtrim(base64_encode(hash('sha256', $codeVerifier, true)), '='), '+/', '-_');

$query = http_build_query([
'client_id' => $client->getKey(),
'redirect_uri' => $redirect = $client->redirect_uris[0],
'response_type' => 'code',
'scope' => 'create read',
'state' => $state = Str::random(40),
'code_challenge' => $codeChallenge,
'code_challenge_method' => 'S256',
]);

$user = UserFactory::new()->create();
$this->actingAs($user, 'web');

$response = $this->get('/oauth/authorize?'.$query);

$response->assertOk();
$response->assertSessionHas('authRequest');
$response->assertSessionHas('authToken');
$json = $response->json();
$this->assertEqualsCanonicalizing(['client', 'user', 'scopes', 'request', 'authToken'], array_keys($json));
$this->assertSame(collect(Passport::scopesFor(['create', 'read']))->toArray(), $json['scopes']);

$response = $this->post('/oauth/authorize', ['auth_token' => $json['authToken']]);
$response->assertRedirect();
$response->assertSessionMissing(['authRequest', 'authToken']);

$location = $response->headers->get('Location');
parse_str(parse_url($location, PHP_URL_QUERY), $params);

$this->assertStringStartsWith($redirect.'?', $location);
$this->assertSame($state, $params['state']);
$this->assertArrayHasKey('code', $params);

$response = $this->post('/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' => $client->getKey(),
'redirect_uri' => $redirect,
'code' => $params['code'],
'code_verifier' => $codeVerifier,
]);

$response->assertOk();
$json = $response->json();
$this->assertArrayHasKey('access_token', $json);
$this->assertArrayHasKey('refresh_token', $json);
$this->assertSame('Bearer', $json['token_type']);
$this->assertSame(31536000, $json['expires_in']);

Route::get('/foo', fn (Request $request) => $request->user()->token()->toJson())
->middleware('auth:api');

$json = $this->withToken($json['access_token'], $json['token_type'])->get('/foo')->json();

$this->assertSame($client->getKey(), $json['oauth_client_id']);
$this->assertEquals($user->getAuthIdentifier(), $json['oauth_user_id']);
$this->assertSame(['create', 'read'], $json['oauth_scopes']);
}

public function testRequireCodeChallenge()
{
$client = ClientFactory::new()->asPublic()->create();

$query = http_build_query([
'client_id' => $client->getKey(),
'redirect_uri' => $client->redirect_uris[0],
'response_type' => 'code',
]);

$user = UserFactory::new()->create();
$this->actingAs($user, 'web');
$response = $this->get('/oauth/authorize?'.$query);

$response->assertStatus(400);
$json = $response->json();

$this->assertSame('invalid_request', $json['error']);
$this->assertSame('Code challenge must be provided for public clients', $json['hint']);
$this->assertArrayHasKey('error_description', $json);
}
}
Loading

0 comments on commit f441a47

Please sign in to comment.