Skip to content

Commit d0fea85

Browse files
author
Bizley
authored
Merge pull request #24 from bizley/3.2.0
3.2.0
2 parents e900f59 + 51382a5 commit d0fea85

File tree

9 files changed

+135
-104
lines changed

9 files changed

+135
-104
lines changed

.github/workflows/tests.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Install PHP
2020
uses: shivammathur/[email protected]
2121
with:
22-
php-version: '7.4'
22+
php-version: '8.0'
2323
extensions: mbstring, intl
2424
coverage: none
2525
env:
@@ -41,15 +41,15 @@ jobs:
4141
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader
4242

4343
- name: PHPStan tests
44-
run: vendor/bin/phpstan analyze -l 8 -a vendor/yiisoft/yii2/Yii.php --no-progress src
44+
run: vendor/bin/phpstan analyze -l 9 -a vendor/yiisoft/yii2/Yii.php --no-progress src
4545

4646
Infection:
4747
name: PHP ${{ matrix.php }}
4848
runs-on: ubuntu-latest
4949
strategy:
5050
fail-fast: false
5151
matrix:
52-
php: ['7.4', '8.0']
52+
php: ['7.4', '8.0', '8.1']
5353

5454
steps:
5555
- name: Checkout
@@ -80,11 +80,11 @@ jobs:
8080
run: composer update --no-interaction --no-progress --optimize-autoloader
8181

8282
- name: Run PHPUnit
83-
if: matrix.php != '7.4'
83+
if: matrix.php != '8.0'
8484
run: vendor/bin/phpunit
8585

8686
- name: Run Infection with PHPUnit
87-
if: matrix.php == '7.4'
87+
if: matrix.php == '8.0'
8888
run: |
8989
mkdir -p build/logs
9090
vendor/bin/phpunit --coverage-xml=build/logs/coverage-xml --log-junit=build/logs/junit.xml

README.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Configuration array can be as the following:
7474
- key (Jwt::KEY) - _string_, default `''`,
7575
- passphrase (Jwt::PASSPHRASE) - _string_, default `''`,
7676
- store (Jwt::STORE) - _string_, default `Jwt::STORE_IN_MEMORY`,
77-
available: `Jwt::STORE_IN_MEMORY`, `Jwt::STORE_LOCAL_FILE_REFERENCE`
77+
available: `Jwt::STORE_IN_MEMORY`, `Jwt::STORE_LOCAL_FILE_REFERENCE` (deprecated since 3.2.0, will be removed in 4.0.0)
7878
(see https://lcobucci-jwt.readthedocs.io/en/latest/configuration/)
7979
- method (Jwt::METHOD) - _string_, default `Jwt::METHOD_PLAIN`,
8080
available: `Jwt::METHOD_PLAIN`, `Jwt::METHOD_BASE64`, `Jwt::METHOD_FILE`
@@ -185,6 +185,9 @@ thrown. There are several ways to provide constraints:
185185
]
186186
```
187187

188+
**Note: By default, this package is not adding any constraints out-of-the-box, you must configure them yourself like
189+
in the examples above.**
190+
188191
## Using component for REST authentication
189192

190193
Configure the `authenticator` behavior in the controller.
@@ -207,7 +210,7 @@ class ExampleController extends Controller
207210

208211
There are special options available:
209212
- jwt - _string_ ID of component (default with `'jwt'`), component configuration _array_, or an instance of `bizley\jwt\Jwt`,
210-
- auth - `\Closure` or `null` (default) - anonymous function with signature `function (\Lcobucci\JWT\Token $token)` that
213+
- auth - callable or `null` (default) - anonymous function with signature `function (\Lcobucci\JWT\Token $token)` that
211214
should return identity of user authenticated with the JWT payload information. If $auth is not provided method
212215
`yii\web\User::loginByAccessToken()` will be called instead.
213216

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"infection/infection": "*",
2727
"phpstan/phpstan": "*",
2828
"phpunit/phpunit": "^9.3",
29-
"roave/security-advisories": "dev-master"
29+
"roave/security-advisories": "dev-latest"
3030
},
3131
"autoload": {
3232
"psr-4": {

infection.json.dist

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"MethodCallRemoval": {
1616
"ignore": [
1717
"bizley\\jwt\\Jwt::init::190",
18-
"bizley\\jwt\\JwtHttpBearerAuth::init::68"
18+
"bizley\\jwt\\JwtHttpBearerAuth::init::69"
1919
]
2020
}
2121
},

phpstan.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/bin/sh
2-
vendor/bin/phpstan analyze -l 8 -a vendor/yiisoft/yii2/Yii.php src
2+
vendor/bin/phpstan analyze -l 9 -a vendor/yiisoft/yii2/Yii.php src

src/Jwt.php

+26-22
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace bizley\jwt;
66

7-
use Closure;
87
use Lcobucci\JWT\Builder;
98
use Lcobucci\JWT\ClaimsFormatter;
109
use Lcobucci\JWT\Configuration;
@@ -24,6 +23,7 @@
2423
use function count;
2524
use function in_array;
2625
use function is_array;
26+
use function is_callable;
2727
use function is_string;
2828
use function reset;
2929
use function strpos;
@@ -49,7 +49,7 @@ class Jwt extends Component
4949
public const EDDSA = 'EdDSA';
5050

5151
public const STORE_IN_MEMORY = 'in_memory';
52-
public const STORE_LOCAL_FILE_REFERENCE = 'local_file_reference';
52+
public const STORE_LOCAL_FILE_REFERENCE = 'local_file_reference'; // deprecated since 3.2.0, will be removed in 4.0.0
5353

5454
public const METHOD_PLAIN = 'plain';
5555
public const METHOD_BASE64 = 'base64';
@@ -68,28 +68,28 @@ class Jwt extends Component
6868
* This can be a simple string, an instance of Key, or a configuration array.
6969
* The configuration takes the following array keys:
7070
* - 'key' => Key's value or path to the key file.
71-
* - 'store' => Either `Jwt::STORE_IN_MEMORY` or `Jwt::STORE_LOCAL_FILE_REFERENCE` - whether to keep the key in
72-
* the memory or as a reference to a local file.
71+
* - 'store' => Either `Jwt::STORE_IN_MEMORY` or `Jwt::STORE_LOCAL_FILE_REFERENCE` (deprecated) -
72+
* whether to keep the key in the memory or as a reference to a local file.
7373
* - 'method' => `Jwt::METHOD_PLAIN`, `Jwt::METHOD_BASE64`, or `Jwt::METHOD_FILE` - whether the key is a plain
7474
* text, base64 encoded text, or a file.
75-
* In case the 'store' is set to `Jwt::STORE_LOCAL_FILE_REFERENCE`, only `Jwt::METHOD_FILE` method
76-
* is available.
75+
* In case the 'store' is set to `Jwt::STORE_LOCAL_FILE_REFERENCE` (deprecated), only
76+
* `Jwt::METHOD_FILE` method is available.
7777
* - 'passphrase' => Key's passphrase.
7878
* In case a simple string is provided (and it does not start with 'file://' or '@') the following configuration
7979
* is assumed:
8080
* [
81-
* 'key' => // the original given value,
82-
* 'store' => Jwt::STORE_IN_MEMORY,
83-
* 'method' => Jwt::METHOD_PLAIN,
84-
* 'passphrase' => '',
81+
* 'key' => // the original given value,
82+
* 'store' => Jwt::STORE_IN_MEMORY,
83+
* 'method' => Jwt::METHOD_PLAIN,
84+
* 'passphrase' => '',
8585
* ]
8686
* In case a simple string is provided and it does start with 'file://' (direct file path) or '@' (Yii alias)
8787
* the following configuration is assumed:
8888
* [
89-
* 'key' => // the original given value,
90-
* 'store' => Jwt::STORE_IN_MEMORY,
91-
* 'method' => Jwt::METHOD_FILE,
92-
* 'passphrase' => '',
89+
* 'key' => // the original given value,
90+
* 'store' => Jwt::STORE_IN_MEMORY,
91+
* 'method' => Jwt::METHOD_FILE,
92+
* 'passphrase' => '',
9393
* ]
9494
* If you want to override the assumed configuration, you must provide it directly.
9595
* @since 3.0.0
@@ -108,13 +108,13 @@ class Jwt extends Component
108108
/**
109109
* @var string|Signer|null Signer ID or Signer instance to be used for signing/verifying.
110110
* See $signers for available values. In case it's not set, no algorithm will be used, which may be handy if you
111-
* want to do some testing but it's NOT recommended for production environments.
111+
* want to do some testing, but it's NOT recommended for production environments.
112112
* @since 3.0.0
113113
*/
114114
public $signer;
115115

116116
/**
117-
* @var array<string, array<mixed>> Default signers configuration. When instantiated it will use selected array to
117+
* @var array<string, string[]> Default signers configuration. When instantiated it will use selected array to
118118
* spread into `Yii::createObject($type, array $params = [])` method so the first array element is $type, and
119119
* the second is $params.
120120
* Since 3.0.0 configuration is done using arrays.
@@ -171,9 +171,9 @@ class Jwt extends Component
171171
public $decoder;
172172

173173
/**
174-
* @var array<array<mixed>>|Validation\Constraint[]|Closure|null List of constraints that will be used to validate
175-
* against or an anonymous function that can be resolved as such list. The signature of the function should be
176-
* `function(\bizley\jwt\Jwt $jwt)` where $jwt will be an instance of this component.
174+
* @var array<array<mixed>|(callable(): mixed)|string>|(callable(): mixed)|null List of constraints that
175+
* will be used to validate against or an anonymous function that can be resolved as such list. The signature of
176+
* the function should be `function(\bizley\jwt\Jwt $jwt)` where $jwt will be an instance of this component.
177177
* For the constraints you can use instances of Lcobucci\JWT\Validation\Constraint or configuration arrays to be
178178
* resolved as such.
179179
* @since 3.0.0
@@ -218,7 +218,7 @@ public function init(): void
218218
}
219219

220220
/**
221-
* @param array<mixed> $config
221+
* @param array<array<mixed>|(callable(): mixed)|string> $config
222222
* @return object
223223
* @throws InvalidConfigException
224224
*/
@@ -325,6 +325,9 @@ private function prepareKey($key): Signer\Key
325325
}
326326

327327
if (is_string($key)) {
328+
if ($key === '') {
329+
throw new InvalidConfigException('Empty string used as a key configuration!');
330+
}
328331
if (strpos($key, '@') === 0) {
329332
$keyConfig = [
330333
self::KEY => Yii::getAlias($key),
@@ -434,8 +437,9 @@ private function prepareValidationConstraints(): array
434437
return $constraints;
435438
}
436439

437-
if ($this->validationConstraints instanceof Closure) {
438-
return ($this->validationConstraints)($this);
440+
if (is_callable($this->validationConstraints)) {
441+
/** @phpstan-ignore-next-line */
442+
return call_user_func($this->validationConstraints, $this);
439443
}
440444

441445
return [];

src/JwtHttpBearerAuth.php

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

55
namespace bizley\jwt;
66

7-
use Closure;
7+
use Lcobucci\JWT\Encoding\CannotDecodeContent;
88
use Lcobucci\JWT\Token;
9+
use Lcobucci\JWT\Validation;
910
use Throwable;
1011
use Yii;
1112
use yii\base\InvalidConfigException;
@@ -42,14 +43,14 @@
4243
class JwtHttpBearerAuth extends HttpBearerAuth
4344
{
4445
/**
45-
* @var string|array<string, mixed>|Jwt application component ID of the JWT handler, configuration array, or JWT handler object
46-
* itself. By default it's assumes that component of ID "jwt" has been configured.
46+
* @var string|array<string, mixed>|Jwt application component ID of the JWT handler, configuration array, or
47+
* JWT handler object itself. By default, it's assumes that component of ID "jwt" has been configured.
4748
*/
4849
public $jwt = 'jwt';
4950

5051
/**
51-
* @var Closure|null anonymous function that should return identity of user authenticated with the JWT payload
52-
* information. It should have the following signature:
52+
* @var (callable(): mixed)|null anonymous function that should return identity of user authenticated with the JWT
53+
* payload information. It should have the following signature:
5354
*
5455
* ```php
5556
* function (Token $token)
@@ -58,7 +59,7 @@ class JwtHttpBearerAuth extends HttpBearerAuth
5859
* where $token is JSON Web Token provided in the HTTP header.
5960
* If $auth is not provided method User::loginByAccessToken() will be called instead.
6061
*/
61-
public ?Closure $auth = null;
62+
public $auth;
6263

6364
/**
6465
* @throws InvalidConfigException
@@ -91,6 +92,13 @@ public function getJwtComponent(): Jwt
9192
* @param Request $request
9293
* @param Response $response
9394
* @return IdentityInterface|null the authenticated user identity. If authentication information is not provided, null will be returned.
95+
* @throws InvalidConfigException When JWT configuration has not been properly initialized.
96+
* @throws CannotDecodeContent When something goes wrong while decoding token.
97+
* @throws Token\InvalidTokenStructure When token string structure is invalid.
98+
* @throws Token\UnsupportedHeaderFound When parsed token has an unsupported header.
99+
* @throws Validation\RequiredConstraintsViolated When constraint is not present in token.
100+
* @throws Validation\NoConstraintsGiven When no constraints are provided.
101+
* @throws Validation\ConstraintViolation When constraint is violated.
94102
* @throws UnauthorizedHttpException if authentication information is provided but is invalid.
95103
*/
96104
public function authenticate($user, $request, $response): ?IdentityInterface // BC signature
@@ -109,19 +117,19 @@ public function authenticate($user, $request, $response): ?IdentityInterface //
109117
$token = $this->processToken($matches[1]);
110118
} catch (Throwable $exception) {
111119
Yii::warning($exception->getMessage(), 'JwtHttpBearerAuth');
112-
$this->fail($response);
120+
throw $exception;
113121
}
114122

115123
if ($token !== null) {
116-
if ($this->auth instanceof Closure) {
124+
if (is_callable($this->auth, true)) {
117125
$identity = call_user_func($this->auth, $token);
118126
} else {
119127
$identity = $user->loginByAccessToken($token->toString(), get_class($this));
120128
}
121129
}
122130

123-
if ($identity === null) {
124-
$this->fail($response);
131+
if (!$identity instanceof IdentityInterface) {
132+
return null;
125133
}
126134

127135
return $identity;

0 commit comments

Comments
 (0)