Skip to content

Commit e305ff0

Browse files
jonericksondriesvintsaxlontaylorotwell
authored
[11.x] Custom authorization view response (#1629)
* Implements authorization view response contract that allows for being overridden with custom views * Updated namespace * Updated namespace * Moved individual arguments to an array of parameters and one argument * Removed authorize return type * Remove old return statement * Add IntelliJ IDE files to gitignore * Formatting * Update tests * Update rest of tests with new response class * Style fixes and make sure parameters pushed to authorization view are in an array. * Remove parameters from authorization view function * Update .gitignore * Update src/Contracts/AuthorizationViewResponse.php Co-authored-by: Choraimy Kroonstuiver <[email protected]> * Update src/Http/Responses/AuthorizationViewResponse.php Co-authored-by: Choraimy Kroonstuiver <[email protected]> * Updated doc block return types * formatting * remove extra line --------- Co-authored-by: Dries Vints <[email protected]> Co-authored-by: Choraimy Kroonstuiver <[email protected]> Co-authored-by: Taylor Otwell <[email protected]>
1 parent 08b1dab commit e305ff0

File tree

6 files changed

+139
-40
lines changed

6 files changed

+139
-40
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Laravel\Passport\Contracts;
4+
5+
use Illuminate\Contracts\Support\Responsable;
6+
7+
interface AuthorizationViewResponse extends Responsable
8+
{
9+
/**
10+
* Specify the parameters that should be passed to the view.
11+
*
12+
* @param array $parameters
13+
* @return $this
14+
*/
15+
public function withParameters($parameters = []);
16+
}

src/Http/Controllers/AuthorizationController.php

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
namespace Laravel\Passport\Http\Controllers;
44

55
use Illuminate\Contracts\Auth\StatefulGuard;
6-
use Illuminate\Contracts\Routing\ResponseFactory;
76
use Illuminate\Http\Request;
87
use Illuminate\Support\Str;
98
use Laravel\Passport\Bridge\User;
109
use Laravel\Passport\ClientRepository;
10+
use Laravel\Passport\Contracts\AuthorizationViewResponse;
1111
use Laravel\Passport\Exceptions\AuthenticationException;
1212
use Laravel\Passport\Passport;
1313
use Laravel\Passport\TokenRepository;
@@ -28,34 +28,33 @@ class AuthorizationController
2828
protected $server;
2929

3030
/**
31-
* The response factory implementation.
31+
* The guard implementation.
3232
*
33-
* @var \Illuminate\Contracts\Routing\ResponseFactory
33+
* @var \Illuminate\Contracts\Auth\StatefulGuard
3434
*/
35-
protected $response;
35+
protected $guard;
3636

3737
/**
38-
* The guard implementation.
38+
* The authorization view response implementation.
3939
*
40-
* @var \Illuminate\Contracts\Auth\StatefulGuard
40+
* @var \Laravel\Passport\Contracts\AuthorizationViewResponse
4141
*/
42-
protected $guard;
42+
protected $response;
4343

4444
/**
4545
* Create a new controller instance.
4646
*
4747
* @param \League\OAuth2\Server\AuthorizationServer $server
48-
* @param \Illuminate\Contracts\Routing\ResponseFactory $response
4948
* @param \Illuminate\Contracts\Auth\StatefulGuard $guard
5049
* @return void
5150
*/
5251
public function __construct(AuthorizationServer $server,
53-
ResponseFactory $response,
54-
StatefulGuard $guard)
52+
StatefulGuard $guard,
53+
AuthorizationViewResponse $response)
5554
{
5655
$this->server = $server;
57-
$this->response = $response;
5856
$this->guard = $guard;
57+
$this->response = $response;
5958
}
6059

6160
/**
@@ -65,7 +64,7 @@ public function __construct(AuthorizationServer $server,
6564
* @param \Illuminate\Http\Request $request
6665
* @param \Laravel\Passport\ClientRepository $clients
6766
* @param \Laravel\Passport\TokenRepository $tokens
68-
* @return \Illuminate\Http\Response
67+
* @return \Laravel\Passport\Contracts\AuthorizationViewResponse
6968
*/
7069
public function authorize(ServerRequestInterface $psrRequest,
7170
Request $request,
@@ -109,7 +108,7 @@ public function authorize(ServerRequestInterface $psrRequest,
109108
$request->session()->put('authToken', $authToken = Str::random());
110109
$request->session()->put('authRequest', $authRequest);
111110

112-
return $this->response->view('passport::authorize', [
111+
return $this->response->withParameters([
113112
'client' => $client,
114113
'user' => $user,
115114
'scopes' => $scopes,
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace Laravel\Passport\Http\Responses;
4+
5+
use Illuminate\Contracts\Support\Responsable;
6+
use Laravel\Passport\Contracts\AuthorizationViewResponse as AuthorizationViewResponseContract;
7+
8+
class AuthorizationViewResponse implements AuthorizationViewResponseContract
9+
{
10+
/**
11+
* The name of the view or the callable used to generate the view.
12+
*
13+
* @var string
14+
*/
15+
protected $view;
16+
17+
/**
18+
* An array of arguments that may be passed to the view response and used in the view.
19+
*
20+
* @var string
21+
*/
22+
protected $parameters;
23+
24+
/**
25+
* Create a new response instance.
26+
*
27+
* @param callable|string $view
28+
* @return void
29+
*/
30+
public function __construct($view)
31+
{
32+
$this->view = $view;
33+
}
34+
35+
/**
36+
* Add parameters to response.
37+
*
38+
* @param array $parameters
39+
* @return $this
40+
*/
41+
public function withParameters($parameters = [])
42+
{
43+
$this->parameters = $parameters;
44+
45+
return $this;
46+
}
47+
48+
/**
49+
* Create an HTTP response that represents the object.
50+
*
51+
* @param \Illuminate\Http\Request $request
52+
* @return \Symfony\Component\HttpFoundation\Response
53+
*/
54+
public function toResponse($request)
55+
{
56+
if (! is_callable($this->view) || is_string($this->view)) {
57+
return response()->view($this->view, $this->parameters);
58+
}
59+
60+
$response = call_user_func($this->view, $this->parameters);
61+
62+
if ($response instanceof Responsable) {
63+
return $response->toResponse($request);
64+
}
65+
66+
return $response;
67+
}
68+
}

src/Passport.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
use DateInterval;
77
use DateTimeInterface;
88
use Illuminate\Contracts\Encryption\Encrypter;
9+
use Laravel\Passport\Contracts\AuthorizationViewResponse as AuthorizationViewResponseContract;
10+
use Laravel\Passport\Http\Responses\AuthorizationViewResponse;
911
use League\OAuth2\Server\ResourceServer;
1012
use Mockery;
1113
use Psr\Http\Message\ServerRequestInterface;
@@ -644,6 +646,19 @@ public static function tokenEncryptionKey(Encrypter $encrypter)
644646
$encrypter->getKey();
645647
}
646648

649+
/**
650+
* Specify which view should be used as the authorization view.
651+
*
652+
* @param callable|string $view
653+
* @return void
654+
*/
655+
public static function authorizationView($view)
656+
{
657+
app()->singleton(AuthorizationViewResponseContract::class, function ($app) use ($view) {
658+
return new AuthorizationViewResponse($view);
659+
});
660+
}
661+
647662
/**
648663
* Configure Passport to not register its routes.
649664
*

src/PassportServiceProvider.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ public function register()
145145
$this->registerJWTParser();
146146
$this->registerResourceServer();
147147
$this->registerGuard();
148+
149+
Passport::authorizationView('passport::authorize');
148150
}
149151

150152
/**

tests/Unit/AuthorizationControllerTest.php

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
namespace Laravel\Passport\Tests\Unit;
44

55
use Illuminate\Contracts\Auth\StatefulGuard;
6-
use Illuminate\Contracts\Routing\ResponseFactory;
76
use Illuminate\Http\Request;
87
use Laravel\Passport\Bridge\Scope;
98
use Laravel\Passport\Client;
109
use Laravel\Passport\ClientRepository;
1110
use Laravel\Passport\Exceptions\AuthenticationException;
1211
use Laravel\Passport\Exceptions\OAuthServerException;
1312
use Laravel\Passport\Http\Controllers\AuthorizationController;
13+
use Laravel\Passport\Http\Responses\AuthorizationViewResponse;
1414
use Laravel\Passport\Passport;
1515
use Laravel\Passport\Token;
1616
use Laravel\Passport\TokenRepository;
@@ -37,10 +37,10 @@ public function test_authorization_view_is_presented()
3737
]);
3838

3939
$server = m::mock(AuthorizationServer::class);
40-
$response = m::mock(ResponseFactory::class);
40+
$response = m::mock(AuthorizationViewResponse::class);
4141
$guard = m::mock(StatefulGuard::class);
4242

43-
$controller = new AuthorizationController($server, $response, $guard);
43+
$controller = new AuthorizationController($server, $guard, $response);
4444

4545
$guard->shouldReceive('guest')->andReturn(false);
4646
$guard->shouldReceive('user')->andReturn($user = m::mock());
@@ -58,21 +58,20 @@ public function test_authorization_view_is_presented()
5858

5959
$clients = m::mock(ClientRepository::class);
6060
$clients->shouldReceive('find')->with(1)->andReturn($client = m::mock(Client::class));
61-
6261
$client->shouldReceive('skipsAuthorization')->andReturn(false);
6362

64-
$response->shouldReceive('view')->once()->andReturnUsing(function ($view, $data) use ($client, $user) {
65-
$this->assertSame('passport::authorize', $view);
63+
$tokens = m::mock(TokenRepository::class);
64+
$tokens->shouldReceive('findValidToken')->with($user, $client)->andReturnNull();
65+
66+
$response->shouldReceive('withParameters')->once()->andReturnUsing(function ($data) use ($client, $user, $request) {
6667
$this->assertEquals($client, $data['client']);
6768
$this->assertEquals($user, $data['user']);
69+
$this->assertEquals($request, $data['request']);
6870
$this->assertSame('description', $data['scopes'][0]->description);
6971

7072
return 'view';
7173
});
7274

73-
$tokens = m::mock(TokenRepository::class);
74-
$tokens->shouldReceive('findValidToken')->with($user, $client)->andReturnNull();
75-
7675
$this->assertSame('view', $controller->authorize(
7776
m::mock(ServerRequestInterface::class), $request, $clients, $tokens
7877
));
@@ -81,10 +80,10 @@ public function test_authorization_view_is_presented()
8180
public function test_authorization_exceptions_are_handled()
8281
{
8382
$server = m::mock(AuthorizationServer::class);
84-
$response = m::mock(ResponseFactory::class);
83+
$response = m::mock(AuthorizationViewResponse::class);
8584
$guard = m::mock(StatefulGuard::class);
8685

87-
$controller = new AuthorizationController($server, $response, $guard);
86+
$controller = new AuthorizationController($server, $guard, $response);
8887

8988
$guard->shouldReceive('guest')->andReturn(false);
9089
$server->shouldReceive('validateAuthorizationRequest')->andThrow(LeagueException::invalidCredentials());
@@ -109,10 +108,10 @@ public function test_request_is_approved_if_valid_token_exists()
109108
]);
110109

111110
$server = m::mock(AuthorizationServer::class);
112-
$response = m::mock(ResponseFactory::class);
111+
$response = m::mock(AuthorizationViewResponse::class);
113112
$guard = m::mock(StatefulGuard::class);
114113

115-
$controller = new AuthorizationController($server, $response, $guard);
114+
$controller = new AuthorizationController($server, $guard, $response);
116115

117116
$guard->shouldReceive('guest')->andReturn(false);
118117
$guard->shouldReceive('user')->andReturn($user = m::mock());
@@ -159,10 +158,10 @@ public function test_request_is_approved_if_client_can_skip_authorization()
159158
]);
160159

161160
$server = m::mock(AuthorizationServer::class);
162-
$response = m::mock(ResponseFactory::class);
161+
$response = m::mock(AuthorizationViewResponse::class);
163162
$guard = m::mock(StatefulGuard::class);
164163

165-
$controller = new AuthorizationController($server, $response, $guard);
164+
$controller = new AuthorizationController($server, $guard, $response);
166165

167166
$guard->shouldReceive('guest')->andReturn(false);
168167
$guard->shouldReceive('user')->andReturn($user = m::mock());
@@ -208,10 +207,10 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal
208207
]);
209208

210209
$server = m::mock(AuthorizationServer::class);
211-
$response = m::mock(ResponseFactory::class);
210+
$response = m::mock(AuthorizationViewResponse::class);
212211
$guard = m::mock(StatefulGuard::class);
213212

214-
$controller = new AuthorizationController($server, $response, $guard);
213+
$controller = new AuthorizationController($server, $guard, $response);
215214

216215
$guard->shouldReceive('guest')->andReturn(false);
217216
$guard->shouldReceive('user')->andReturn($user = m::mock());
@@ -235,10 +234,10 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal
235234
$tokens = m::mock(TokenRepository::class);
236235
$tokens->shouldNotReceive('findValidToken');
237236

238-
$response->shouldReceive('view')->once()->andReturnUsing(function ($view, $data) use ($client, $user) {
239-
$this->assertSame('passport::authorize', $view);
237+
$response->shouldReceive('withParameters')->once()->andReturnUsing(function ($data) use ($client, $user, $request) {
240238
$this->assertEquals($client, $data['client']);
241239
$this->assertEquals($user, $data['user']);
240+
$this->assertEquals($request, $data['request']);
242241
$this->assertSame('description', $data['scopes'][0]->description);
243242

244243
return 'view';
@@ -258,10 +257,10 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none()
258257
]);
259258

260259
$server = m::mock(AuthorizationServer::class);
261-
$response = m::mock(ResponseFactory::class);
260+
$response = m::mock(AuthorizationViewResponse::class);
262261
$guard = m::mock(StatefulGuard::class);
263262

264-
$controller = new AuthorizationController($server, $response, $guard);
263+
$controller = new AuthorizationController($server, $guard, $response);
265264

266265
$guard->shouldReceive('guest')->andReturn(false);
267266
$guard->shouldReceive('user')->andReturn($user = m::mock());
@@ -300,10 +299,10 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none()
300299
public function test_authorization_denied_if_unauthenticated_and_request_has_prompt_equals_to_none()
301300
{
302301
$server = m::mock(AuthorizationServer::class);
303-
$response = m::mock(ResponseFactory::class);
302+
$response = m::mock(AuthorizationViewResponse::class);
304303
$guard = m::mock(StatefulGuard::class);
305304

306-
$controller = new AuthorizationController($server, $response, $guard);
305+
$controller = new AuthorizationController($server, $guard, $response);
307306

308307
$guard->shouldReceive('guest')->andReturn(true);
309308
$server->shouldReceive('validateAuthorizationRequest')
@@ -341,10 +340,10 @@ public function test_logout_and_prompt_login_if_request_has_prompt_equals_to_log
341340
$this->expectException(AuthenticationException::class);
342341

343342
$server = m::mock(AuthorizationServer::class);
344-
$response = m::mock(ResponseFactory::class);
343+
$response = m::mock(AuthorizationViewResponse::class);
345344
$guard = m::mock(StatefulGuard::class);
346345

347-
$controller = new AuthorizationController($server, $response, $guard);
346+
$controller = new AuthorizationController($server, $guard, $response);
348347

349348
$guard->shouldReceive('guest')->andReturn(false);
350349
$server->shouldReceive('validateAuthorizationRequest')->once();
@@ -372,10 +371,10 @@ public function test_user_should_be_authenticated()
372371
$this->expectException(AuthenticationException::class);
373372

374373
$server = m::mock(AuthorizationServer::class);
375-
$response = m::mock(ResponseFactory::class);
374+
$response = m::mock(AuthorizationViewResponse::class);
376375
$guard = m::mock(StatefulGuard::class);
377376

378-
$controller = new AuthorizationController($server, $response, $guard);
377+
$controller = new AuthorizationController($server, $guard, $response);
379378

380379
$guard->shouldReceive('guest')->andReturn(true);
381380
$server->shouldReceive('validateAuthorizationRequest')->once();

0 commit comments

Comments
 (0)