Skip to content

Commit 6fafccc

Browse files
[13.x] Add new EnsureClientIsResourceOwner middleware (#1794)
* add new middleware and rename old ones * fix tests * upgrade guide * formatting
1 parent ef122ad commit 6fafccc

14 files changed

+218
-301
lines changed

UPGRADE.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ When authenticating users via bearer tokens, the `User` model's `token` method n
6666

6767
### Renamed Middlewares
6868

69-
PR: https://github.com/laravel/passport/pull/1792
69+
PR: https://github.com/laravel/passport/pull/1792, https://github.com/laravel/passport/pull/1794
7070

71-
Passport's `CheckClientCredentials` and `CheckClientCredentialsForAnyScope` middleware have been renamed to better reflect their functionality:
71+
The following Passport's middlewares have been renamed to better reflect their functionality:
7272

73+
* `Laravel\Passport\Http\Middleware\CheckScopes` class has been renamed to `CheckToken`.
74+
* `Laravel\Passport\Http\Middleware\CheckForAnyScope` class has been renamed to `CheckTokenForAnyScope`.
7375
* `Laravel\Passport\Http\Middleware\CheckClientCredentials` class has been renamed to `CheckToken`.
7476
* `Laravel\Passport\Http\Middleware\CheckClientCredentialsForAnyScope` class has been renamed to `CheckTokenForAnyScope`.
7577
* `Laravel\Passport\Http\Middleware\CheckCredentials` abstract class has been renamed to `ValidateToken`.

src/Http/Middleware/CheckForAnyScope.php

-48
This file was deleted.

src/Http/Middleware/CheckScopes.php

-48
This file was deleted.

src/Http/Middleware/CheckToken.php

+2-8
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,11 @@ class CheckToken extends ValidateToken
1010
/**
1111
* Determine if the token has all the given scopes.
1212
*
13-
* @param string[] $scopes
14-
*
1513
* @throws \Laravel\Passport\Exceptions\MissingScopeException
1614
*/
17-
protected function hasScopes(AccessToken $token, array $scopes): void
15+
protected function validate(AccessToken $token, string ...$params): void
1816
{
19-
if (in_array('*', $token->oauth_scopes)) {
20-
return;
21-
}
22-
23-
foreach ($scopes as $scope) {
17+
foreach ($params as $scope) {
2418
if ($token->cant($scope)) {
2519
throw new MissingScopeException($scope);
2620
}

src/Http/Middleware/CheckTokenForAnyScope.php

+3-9
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,16 @@ class CheckTokenForAnyScope extends ValidateToken
1010
/**
1111
* Determine if the token has at least one of the given scopes.
1212
*
13-
* @param string[] $scopes
14-
*
1513
* @throws \Laravel\Passport\Exceptions\MissingScopeException
1614
*/
17-
protected function hasScopes(AccessToken $token, array $scopes): void
15+
protected function validate(AccessToken $token, string ...$params): void
1816
{
19-
if (in_array('*', $token->oauth_scopes)) {
20-
return;
21-
}
22-
23-
foreach ($scopes as $scope) {
17+
foreach ($params as $scope) {
2418
if ($token->can($scope)) {
2519
return;
2620
}
2721
}
2822

29-
throw new MissingScopeException($scopes);
23+
throw new MissingScopeException($params);
3024
}
3125
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Laravel\Passport\Http\Middleware;
4+
5+
use Illuminate\Auth\AuthenticationException;
6+
use Laravel\Passport\AccessToken;
7+
use Laravel\Passport\Exceptions\MissingScopeException;
8+
9+
class EnsureClientIsResourceOwner extends ValidateToken
10+
{
11+
/**
12+
* Determine if the token's client is the resource owner and has all the given scopes.
13+
*
14+
* @throws \Exception
15+
*/
16+
protected function validate(AccessToken $token, string ...$params): void
17+
{
18+
if ($token->oauth_user_id !== $token->oauth_client_id) {
19+
throw new AuthenticationException;
20+
}
21+
22+
foreach ($params as $scope) {
23+
if ($token->cant($scope)) {
24+
throw new MissingScopeException($scope);
25+
}
26+
}
27+
}
28+
}

src/Http/Middleware/ValidateToken.php

+35-17
Original file line numberDiff line numberDiff line change
@@ -22,48 +22,66 @@ public function __construct(
2222
}
2323

2424
/**
25-
* Specify the scopes for the middleware.
25+
* Specify the parameters for the middleware.
2626
*
27-
* @param string[]|string ...$scopes
27+
* @param string[]|string ...$params
2828
*/
29-
public static function using(...$scopes): string
29+
public static function using(...$params): string
3030
{
31-
if (is_array($scopes[0])) {
32-
return static::class.':'.implode(',', $scopes[0]);
31+
if (is_array($params[0])) {
32+
return static::class.':'.implode(',', $params[0]);
3333
}
3434

35-
return static::class.':'.implode(',', $scopes);
35+
return static::class.':'.implode(',', $params);
3636
}
3737

3838
/**
3939
* Handle an incoming request.
4040
*
4141
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
42-
* @param string[]|string ...$scopes
42+
* @param string[]|string ...$params
43+
*/
44+
public function handle(Request $request, Closure $next, string ...$params): Response
45+
{
46+
$token = $this->validateToken($request);
47+
48+
$this->validate($token, ...$params);
49+
50+
return $next($request);
51+
}
52+
53+
/**
54+
* Validate and get the request's access token.
4355
*
4456
* @throws \Laravel\Passport\Exceptions\AuthenticationException
4557
*/
46-
public function handle(Request $request, Closure $next, string ...$scopes): Response
58+
protected function validateToken(Request $request): AccessToken
4759
{
48-
$psr = (new PsrHttpFactory())->createRequest($request);
60+
// If the user is authenticated and already has an access token set via
61+
// the token guard, there's no need to validate the request's bearer
62+
// token again, so we'll return the access token as the valid one.
63+
if ($request->user()?->token()) {
64+
return $request->user()->token();
65+
}
66+
67+
// Otherwise, we will convert the request to a PSR-7 implementation and
68+
// pass it to the OAuth2 server to be validated. If the bearer token
69+
// passed the validation, we will return an access token instance.
70+
$psrRequest = (new PsrHttpFactory())->createRequest($request);
4971

5072
try {
51-
$psr = $this->server->validateAuthenticatedRequest($psr);
73+
$psrRequest = $this->server->validateAuthenticatedRequest($psrRequest);
5274
} catch (OAuthServerException) {
5375
throw new AuthenticationException;
5476
}
5577

56-
$this->hasScopes(AccessToken::fromPsrRequest($psr), $scopes);
57-
58-
return $next($request);
78+
return AccessToken::fromPsrRequest($psrRequest);
5979
}
6080

6181
/**
62-
* Determine if the token has the given scopes.
63-
*
64-
* @param string[] $scopes
82+
* Validate the given access token.
6583
*
6684
* @throws \Laravel\Passport\Exceptions\MissingScopeException
6785
*/
68-
abstract protected function hasScopes(AccessToken $token, array $scopes): void;
86+
abstract protected function validate(AccessToken $token, string ...$params): void;
6987
}

tests/Feature/ActingAsTest.php

+18-18
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
use Illuminate\Contracts\Routing\Registrar;
66
use Illuminate\Support\Facades\Route;
7-
use Laravel\Passport\Http\Middleware\CheckForAnyScope;
8-
use Laravel\Passport\Http\Middleware\CheckScopes;
7+
use Laravel\Passport\Http\Middleware\CheckToken;
8+
use Laravel\Passport\Http\Middleware\CheckTokenForAnyScope;
99
use Laravel\Passport\Passport;
1010
use Workbench\App\Models\User;
1111

@@ -38,7 +38,7 @@ public function testActingAsWhenTheRouteIsProtectedByCheckScopesMiddleware()
3838

3939
$router->get('/foo', function () {
4040
return 'bar';
41-
})->middleware(CheckScopes::class.':admin,footest');
41+
})->middleware(CheckToken::class.':admin,footest');
4242

4343
Passport::actingAs(new User(), ['admin', 'footest']);
4444

@@ -49,23 +49,23 @@ public function testActingAsWhenTheRouteIsProtectedByCheckScopesMiddleware()
4949

5050
public function testItCanGenerateDefinitionViaStaticMethod()
5151
{
52-
$signature = (string) CheckScopes::using('admin');
53-
$this->assertSame('Laravel\Passport\Http\Middleware\CheckScopes:admin', $signature);
52+
$signature = (string) CheckToken::using('admin');
53+
$this->assertSame('Laravel\Passport\Http\Middleware\CheckToken:admin', $signature);
5454

55-
$signature = (string) CheckScopes::using('admin', 'footest');
56-
$this->assertSame('Laravel\Passport\Http\Middleware\CheckScopes:admin,footest', $signature);
55+
$signature = (string) CheckToken::using('admin', 'footest');
56+
$this->assertSame('Laravel\Passport\Http\Middleware\CheckToken:admin,footest', $signature);
5757

58-
$signature = (string) CheckScopes::using(['admin', 'footest']);
59-
$this->assertSame('Laravel\Passport\Http\Middleware\CheckScopes:admin,footest', $signature);
58+
$signature = (string) CheckToken::using(['admin', 'footest']);
59+
$this->assertSame('Laravel\Passport\Http\Middleware\CheckToken:admin,footest', $signature);
6060

61-
$signature = (string) CheckForAnyScope::using('admin');
62-
$this->assertSame('Laravel\Passport\Http\Middleware\CheckForAnyScope:admin', $signature);
61+
$signature = (string) CheckTokenForAnyScope::using('admin');
62+
$this->assertSame('Laravel\Passport\Http\Middleware\CheckTokenForAnyScope:admin', $signature);
6363

64-
$signature = (string) CheckForAnyScope::using('admin', 'footest');
65-
$this->assertSame('Laravel\Passport\Http\Middleware\CheckForAnyScope:admin,footest', $signature);
64+
$signature = (string) CheckTokenForAnyScope::using('admin', 'footest');
65+
$this->assertSame('Laravel\Passport\Http\Middleware\CheckTokenForAnyScope:admin,footest', $signature);
6666

67-
$signature = (string) CheckForAnyScope::using(['admin', 'footest']);
68-
$this->assertSame('Laravel\Passport\Http\Middleware\CheckForAnyScope:admin,footest', $signature);
67+
$signature = (string) CheckTokenForAnyScope::using(['admin', 'footest']);
68+
$this->assertSame('Laravel\Passport\Http\Middleware\CheckTokenForAnyScope:admin,footest', $signature);
6969
}
7070

7171
public function testActingAsWhenTheRouteIsProtectedByCheckForAnyScopeMiddleware()
@@ -77,7 +77,7 @@ public function testActingAsWhenTheRouteIsProtectedByCheckForAnyScopeMiddleware(
7777

7878
$router->get('/foo', function () {
7979
return 'bar';
80-
})->middleware(CheckForAnyScope::class.':admin,footest');
80+
})->middleware(CheckTokenForAnyScope::class.':admin,footest');
8181

8282
Passport::actingAs(new User(), ['footest']);
8383

@@ -92,7 +92,7 @@ public function testActingAsWhenTheRouteIsProtectedByCheckScopesMiddlewareWithIn
9292

9393
$this->withoutExceptionHandling();
9494

95-
Route::middleware(CheckScopes::class.':foo:bar,baz:qux')->get('/foo', function () {
95+
Route::middleware(CheckToken::class.':foo:bar,baz:qux')->get('/foo', function () {
9696
return 'bar';
9797
});
9898

@@ -109,7 +109,7 @@ public function testActingAsWhenTheRouteIsProtectedByCheckForAnyScopeMiddlewareW
109109

110110
$this->withoutExceptionHandling();
111111

112-
Route::middleware(CheckForAnyScope::class.':foo:baz,baz:qux')->get('/foo', function () {
112+
Route::middleware(CheckTokenForAnyScope::class.':foo:baz,baz:qux')->get('/foo', function () {
113113
return 'bar';
114114
});
115115

tests/Feature/AuthorizationCodeGrantTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public function testSkipsAuthorizationWhenHasGrantedScopes()
142142
'client_secret' => $client->plainSecret,
143143
'redirect_uri' => $redirect,
144144
'code' => $params['code'],
145-
]);
145+
])->assertOk();
146146

147147
$query = http_build_query([
148148
'client_id' => $client->getKey(),

0 commit comments

Comments
 (0)