Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/Http/Controllers/AuthorizationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,22 @@ public function authorize(
($psrRequest->getQueryParams()['response_type'] ?? null) === 'token'
);

$prompt = $request->string('prompt')->explode(' ')->map(trim(...))->filter()->values();

// If the prompt parameter includes "none", all other prompt values will be ignored
// An error will be returned if the end-user is not already authenticated or the
// OAuth client does not have pre-configured consent for the requested scopes.
if ($prompt->contains('none')) {
$prompt = collect(['none']);
}

if ($this->guard->guest()) {
$request->input('prompt') === 'none'
$prompt->contains('none')
? throw OAuthServerException::loginRequired($authRequest)
: $this->promptForLogin($request);
}

if ($request->input('prompt') === 'login' &&
if ($prompt->contains('login') &&
! $request->session()->get('promptedForLogin', false)) {
$this->guard->logout();
$request->session()->invalidate();
Expand All @@ -72,12 +81,12 @@ public function authorize(
$scopes = $this->parseScopes($authRequest);
$client = $this->clients->find($authRequest->getClient()->getIdentifier());

if ($request->input('prompt') !== 'consent' &&
if ($prompt->doesntContain('consent') &&
($client->skipsAuthorization($user, $scopes) || $this->hasGrantedScopes($user, $client, $scopes))) {
return $this->approveRequest($authRequest, $psrResponse);
}

if ($request->input('prompt') === 'none') {
if ($prompt->contains('none')) {
throw OAuthServerException::consentRequired($authRequest);
}

Expand Down
83 changes: 83 additions & 0 deletions tests/Feature/AuthorizationCodeGrantTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,89 @@ public function testPromptLogin()
$response->assertRedirectToRoute('login');
}

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

$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' => $client->redirect_uris[0],
'response_type' => 'code',
'scope' => 'create read',
'state' => Str::random(40),
'prompt' => 'login consent',
]);

$this->get('/oauth/authorize?'.$query)
->assertSessionHas('promptedForLogin', true)
->assertRedirectToRoute('login');

$intendedUrl = session()->get('url.intended');
parse_str(parse_url($intendedUrl, PHP_URL_QUERY), $params);

dump($params);

$this->actingAs($user, 'web');
$json = $this->get($intendedUrl)
->assertOk()
->assertSessionHas('authRequest')
->assertSessionHas('authToken')
->json();

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

public function testPromptContainsNone()
{
$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 login consent select_account',
]);

$this->actingAs(UserFactory::new()->create(), 'web');
$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('consent_required', $params['error']);
$this->assertArrayHasKey('error_description', $params);
}

public function testUnauthorizedClient()
{
$client = ClientFactory::new()->create([
Expand Down
17 changes: 9 additions & 8 deletions tests/Unit/AuthorizationControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Laravel\Passport\Bridge\Scope;
use Laravel\Passport\Client;
use Laravel\Passport\ClientRepository;
Expand Down Expand Up @@ -51,7 +52,7 @@ public function test_authorization_view_is_presented()
$session->shouldReceive('put')->withSomeOfArgs('authToken');
$session->shouldReceive('put')->with('authRequest', $authRequest);
$session->shouldReceive('forget')->with('promptedForLogin')->once();
$request->shouldReceive('input')->with('prompt')->andReturn(null);
$request->shouldReceive('string')->with('prompt')->andReturn(Str::of(null));

$authRequest->shouldReceive('getClient->getIdentifier')->andReturn(1);
$authRequest->shouldReceive('getScopes')->andReturn([new Scope('scope-1')]);
Expand Down Expand Up @@ -134,7 +135,7 @@ public function test_request_is_approved_if_valid_token_exists()
$session->shouldReceive('forget')->with('promptedForLogin')->once();
$user->shouldReceive('getAuthIdentifier')->andReturn(1);
$request->shouldNotReceive('session');
$request->shouldReceive('input')->with('prompt')->andReturn(null);
$request->shouldReceive('string')->with('prompt')->andReturn(Str::of(null));

$authRequest->shouldReceive('getClient->getIdentifier')->once()->andReturn(1);
$authRequest->shouldReceive('getScopes')->once()->andReturn([new Scope('scope-1')]);
Expand Down Expand Up @@ -182,7 +183,7 @@ public function test_request_is_approved_if_client_can_skip_authorization()
$session->shouldReceive('forget')->with('promptedForLogin')->once();
$user->shouldReceive('getAuthIdentifier')->andReturn(1);
$request->shouldNotReceive('session');
$request->shouldReceive('input')->with('prompt')->andReturn(null);
$request->shouldReceive('string')->with('prompt')->andReturn(Str::of(null));

$authRequest->shouldReceive('getClient->getIdentifier')->once()->andReturn(1);
$authRequest->shouldReceive('getScopes')->once()->andReturn([new Scope('scope-1')]);
Expand Down Expand Up @@ -226,7 +227,7 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal
$session->shouldReceive('put')->withSomeOfArgs('authToken');
$session->shouldReceive('put')->with('authRequest', $authRequest);
$session->shouldReceive('forget')->with('promptedForLogin')->once();
$request->shouldReceive('input')->with('prompt')->andReturn('consent');
$request->shouldReceive('string')->with('prompt')->andReturn(Str::of('consent'));

$authRequest->shouldReceive('getClient->getIdentifier')->once()->andReturn(1);
$authRequest->shouldReceive('getScopes')->once()->andReturn([new Scope('scope-1')]);
Expand Down Expand Up @@ -275,7 +276,7 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none()
$request->shouldReceive('session')->andReturn($session = m::mock());
$session->shouldReceive('forget')->with('promptedForLogin')->once();
$user->shouldReceive('getAuthIdentifier')->andReturn(1);
$request->shouldReceive('input')->with('prompt')->andReturn('none');
$request->shouldReceive('string')->with('prompt')->andReturn(Str::of('none'));

$authRequest->shouldReceive('getClient->getIdentifier')->once()->andReturn(1);
$authRequest->shouldReceive('getScopes')->once()->andReturn([new Scope('scope-1')]);
Expand Down Expand Up @@ -326,7 +327,7 @@ public function test_authorization_denied_if_unauthenticated_and_request_has_pro

$request = m::mock(Request::class);
$request->shouldNotReceive('user');
$request->shouldReceive('input')->with('prompt')->andReturn('none');
$request->shouldReceive('string')->with('prompt')->andReturn(Str::of('none'));

$authRequest->shouldNotReceive('setUser');
$authRequest->shouldReceive('setAuthorizationApproved')->with(false);
Expand Down Expand Up @@ -378,7 +379,7 @@ public function test_logout_and_prompt_login_if_request_has_prompt_equals_to_log
$session->shouldReceive('get')->with('promptedForLogin', false)->once()->andReturn(false);
$session->shouldReceive('put')->with('promptedForLogin', true)->once();
$session->shouldNotReceive('forget')->with('promptedForLogin');
$request->shouldReceive('input')->with('prompt')->andReturn('login');
$request->shouldReceive('string')->with('prompt')->andReturn(Str::of('login'));

$clients = m::mock(ClientRepository::class);

Expand Down Expand Up @@ -408,7 +409,7 @@ public function test_user_should_be_authenticated()
$request->shouldReceive('session')->andReturn($session = m::mock());
$session->shouldReceive('put')->with('promptedForLogin', true)->once();
$session->shouldNotReceive('forget')->with('promptedForLogin');
$request->shouldReceive('input')->with('prompt')->andReturn(null);
$request->shouldReceive('string')->with('prompt')->andReturn(Str::of(null));

$clients = m::mock(ClientRepository::class);

Expand Down
Loading