Skip to content

Commit

Permalink
Merge pull request #24 from bizley/3.2.0
Browse files Browse the repository at this point in the history
3.2.0
  • Loading branch information
Bizley authored Feb 12, 2022
2 parents e900f59 + 51382a5 commit d0fea85
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 104 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Install PHP
uses: shivammathur/[email protected]
with:
php-version: '7.4'
php-version: '8.0'
extensions: mbstring, intl
coverage: none
env:
Expand All @@ -41,15 +41,15 @@ jobs:
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader

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

Infection:
name: PHP ${{ matrix.php }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ['7.4', '8.0']
php: ['7.4', '8.0', '8.1']

steps:
- name: Checkout
Expand Down Expand Up @@ -80,11 +80,11 @@ jobs:
run: composer update --no-interaction --no-progress --optimize-autoloader

- name: Run PHPUnit
if: matrix.php != '7.4'
if: matrix.php != '8.0'
run: vendor/bin/phpunit

- name: Run Infection with PHPUnit
if: matrix.php == '7.4'
if: matrix.php == '8.0'
run: |
mkdir -p build/logs
vendor/bin/phpunit --coverage-xml=build/logs/coverage-xml --log-junit=build/logs/junit.xml
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Configuration array can be as the following:
- key (Jwt::KEY) - _string_, default `''`,
- passphrase (Jwt::PASSPHRASE) - _string_, default `''`,
- store (Jwt::STORE) - _string_, default `Jwt::STORE_IN_MEMORY`,
available: `Jwt::STORE_IN_MEMORY`, `Jwt::STORE_LOCAL_FILE_REFERENCE`
available: `Jwt::STORE_IN_MEMORY`, `Jwt::STORE_LOCAL_FILE_REFERENCE` (deprecated since 3.2.0, will be removed in 4.0.0)
(see https://lcobucci-jwt.readthedocs.io/en/latest/configuration/)
- method (Jwt::METHOD) - _string_, default `Jwt::METHOD_PLAIN`,
available: `Jwt::METHOD_PLAIN`, `Jwt::METHOD_BASE64`, `Jwt::METHOD_FILE`
Expand Down Expand Up @@ -185,6 +185,9 @@ thrown. There are several ways to provide constraints:
]
```

**Note: By default, this package is not adding any constraints out-of-the-box, you must configure them yourself like
in the examples above.**

## Using component for REST authentication

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

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

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"infection/infection": "*",
"phpstan/phpstan": "*",
"phpunit/phpunit": "^9.3",
"roave/security-advisories": "dev-master"
"roave/security-advisories": "dev-latest"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion infection.json.dist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"MethodCallRemoval": {
"ignore": [
"bizley\\jwt\\Jwt::init::190",
"bizley\\jwt\\JwtHttpBearerAuth::init::68"
"bizley\\jwt\\JwtHttpBearerAuth::init::69"
]
}
},
Expand Down
2 changes: 1 addition & 1 deletion phpstan.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/bin/sh
vendor/bin/phpstan analyze -l 8 -a vendor/yiisoft/yii2/Yii.php src
vendor/bin/phpstan analyze -l 9 -a vendor/yiisoft/yii2/Yii.php src
48 changes: 26 additions & 22 deletions src/Jwt.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace bizley\jwt;

use Closure;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\ClaimsFormatter;
use Lcobucci\JWT\Configuration;
Expand All @@ -24,6 +23,7 @@
use function count;
use function in_array;
use function is_array;
use function is_callable;
use function is_string;
use function reset;
use function strpos;
Expand All @@ -49,7 +49,7 @@ class Jwt extends Component
public const EDDSA = 'EdDSA';

public const STORE_IN_MEMORY = 'in_memory';
public const STORE_LOCAL_FILE_REFERENCE = 'local_file_reference';
public const STORE_LOCAL_FILE_REFERENCE = 'local_file_reference'; // deprecated since 3.2.0, will be removed in 4.0.0

public const METHOD_PLAIN = 'plain';
public const METHOD_BASE64 = 'base64';
Expand All @@ -68,28 +68,28 @@ class Jwt extends Component
* This can be a simple string, an instance of Key, or a configuration array.
* The configuration takes the following array keys:
* - 'key' => Key's value or path to the key file.
* - 'store' => Either `Jwt::STORE_IN_MEMORY` or `Jwt::STORE_LOCAL_FILE_REFERENCE` - whether to keep the key in
* the memory or as a reference to a local file.
* - 'store' => Either `Jwt::STORE_IN_MEMORY` or `Jwt::STORE_LOCAL_FILE_REFERENCE` (deprecated) -
* whether to keep the key in the memory or as a reference to a local file.
* - 'method' => `Jwt::METHOD_PLAIN`, `Jwt::METHOD_BASE64`, or `Jwt::METHOD_FILE` - whether the key is a plain
* text, base64 encoded text, or a file.
* In case the 'store' is set to `Jwt::STORE_LOCAL_FILE_REFERENCE`, only `Jwt::METHOD_FILE` method
* is available.
* In case the 'store' is set to `Jwt::STORE_LOCAL_FILE_REFERENCE` (deprecated), only
* `Jwt::METHOD_FILE` method is available.
* - 'passphrase' => Key's passphrase.
* In case a simple string is provided (and it does not start with 'file://' or '@') the following configuration
* is assumed:
* [
* 'key' => // the original given value,
* 'store' => Jwt::STORE_IN_MEMORY,
* 'method' => Jwt::METHOD_PLAIN,
* 'passphrase' => '',
* 'key' => // the original given value,
* 'store' => Jwt::STORE_IN_MEMORY,
* 'method' => Jwt::METHOD_PLAIN,
* 'passphrase' => '',
* ]
* In case a simple string is provided and it does start with 'file://' (direct file path) or '@' (Yii alias)
* the following configuration is assumed:
* [
* 'key' => // the original given value,
* 'store' => Jwt::STORE_IN_MEMORY,
* 'method' => Jwt::METHOD_FILE,
* 'passphrase' => '',
* 'key' => // the original given value,
* 'store' => Jwt::STORE_IN_MEMORY,
* 'method' => Jwt::METHOD_FILE,
* 'passphrase' => '',
* ]
* If you want to override the assumed configuration, you must provide it directly.
* @since 3.0.0
Expand All @@ -108,13 +108,13 @@ class Jwt extends Component
/**
* @var string|Signer|null Signer ID or Signer instance to be used for signing/verifying.
* See $signers for available values. In case it's not set, no algorithm will be used, which may be handy if you
* want to do some testing but it's NOT recommended for production environments.
* want to do some testing, but it's NOT recommended for production environments.
* @since 3.0.0
*/
public $signer;

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

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

/**
* @param array<mixed> $config
* @param array<array<mixed>|(callable(): mixed)|string> $config
* @return object
* @throws InvalidConfigException
*/
Expand Down Expand Up @@ -325,6 +325,9 @@ private function prepareKey($key): Signer\Key
}

if (is_string($key)) {
if ($key === '') {
throw new InvalidConfigException('Empty string used as a key configuration!');
}
if (strpos($key, '@') === 0) {
$keyConfig = [
self::KEY => Yii::getAlias($key),
Expand Down Expand Up @@ -434,8 +437,9 @@ private function prepareValidationConstraints(): array
return $constraints;
}

if ($this->validationConstraints instanceof Closure) {
return ($this->validationConstraints)($this);
if (is_callable($this->validationConstraints)) {
/** @phpstan-ignore-next-line */
return call_user_func($this->validationConstraints, $this);
}

return [];
Expand Down
28 changes: 18 additions & 10 deletions src/JwtHttpBearerAuth.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

namespace bizley\jwt;

use Closure;
use Lcobucci\JWT\Encoding\CannotDecodeContent;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation;
use Throwable;
use Yii;
use yii\base\InvalidConfigException;
Expand Down Expand Up @@ -42,14 +43,14 @@
class JwtHttpBearerAuth extends HttpBearerAuth
{
/**
* @var string|array<string, mixed>|Jwt application component ID of the JWT handler, configuration array, or JWT handler object
* itself. By default it's assumes that component of ID "jwt" has been configured.
* @var string|array<string, mixed>|Jwt application component ID of the JWT handler, configuration array, or
* JWT handler object itself. By default, it's assumes that component of ID "jwt" has been configured.
*/
public $jwt = 'jwt';

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

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

if ($token !== null) {
if ($this->auth instanceof Closure) {
if (is_callable($this->auth, true)) {
$identity = call_user_func($this->auth, $token);
} else {
$identity = $user->loginByAccessToken($token->toString(), get_class($this));
}
}

if ($identity === null) {
$this->fail($response);
if (!$identity instanceof IdentityInterface) {
return null;
}

return $identity;
Expand Down
Loading

0 comments on commit d0fea85

Please sign in to comment.