fix composite auth ignore only/except filters of auth methods (#19418)

* fix compositeAuth ignore only/except filters of child auth methods

* fix

* add tests for wrong token

* fix

* update changelog

* Update CHANGELOG.md

Co-authored-by: Bizley <pawel@positive.codes>
This commit is contained in:
Alexey
2022-06-15 11:06:38 +03:00
committed by GitHub
parent f2b2d576be
commit f72310c398
3 changed files with 144 additions and 16 deletions

View File

@ -29,6 +29,7 @@ Yii Framework 2 Change Log
- Bug #19368: Fix PHP 8.1 error when `$fileMimeType` is `null` in `yii\validators\FileValidator::validateMimeType()` (bizley)
- Enh #19384: Normalize `setBodyParams()` and `getBodyParam()` in `yii\web\Request` (WinterSilence, albertborsos)
- Bug #19386: Fix recursive calling `yii\helpers\BaseArrayHelper::htmlDecode()` (WinterSilence)
- Bug #19418: Fix `yii\filters\auth\CompositeAuth` ignoring `only` and `except` options (lesha724)
- Enh #19401: Delay `exit(1)` in `yii\base\ErrorHandler::handleFatalError` (arrilot)
- Bug #19402: Add shutdown event and fix working directory in `yii\base\ErrorHandler` (WinterSilence)
- Enh #19416: Update and improve configurations for `yii\console\controllers\MessageController` (WinterSilence)

View File

@ -70,9 +70,11 @@ class CompositeAuth extends AuthMethod
}
}
$identity = $auth->authenticate($user, $request, $response);
if ($identity !== null) {
return $identity;
if (isset($this->owner->action) && $auth->isActive($this->owner->action)) {
$identity = $auth->authenticate($user, $request, $response);
if ($identity !== null) {
return $identity;
}
}
}

View File

@ -8,21 +8,40 @@
namespace yiiunit\framework\filters\auth;
use Yii;
use yii\filters\auth\AuthMethod;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\HttpHeaderAuth;
use yii\rest\Controller;
use yii\web\UnauthorizedHttpException;
use yiiunit\framework\web\UserIdentity;
/**
* @author Ezekiel Fernandez <ezekiel_p_fernandez@yahoo.com>
*/
class TestAuth extends AuthMethod
class TestAuth extends HttpHeaderAuth
{
public function authenticate($user, $request, $response)
{
return $user;
$authHeader = $request->getHeaders()->get($this->header);
if ($authHeader !== null) {
if ($this->pattern !== null) {
if (preg_match($this->pattern, $authHeader, $matches)) {
$authHeader = $matches[1];
} else {
return null;
}
}
$identity = \yiiunit\framework\filters\stubs\UserIdentity::findIdentity($authHeader);
if ($identity === null) {
$this->challenge($response);
$this->handleFailure($response);
}
return $identity;
}
return null;
}
}
@ -30,6 +49,8 @@ class TestController extends Controller
{
public $authMethods = [];
public $optional = [];
public function actionA()
{
return 'success';
@ -73,6 +94,7 @@ class TestController extends Controller
'authMethods' => $this->authMethods ?: [
TestAuth::className(),
],
'optional' => $this->optional
],
];
}
@ -107,6 +129,7 @@ class CompositeAuthTest extends \yiiunit\TestCase
public function testCallingRunWithCompleteRoute()
{
/** @var TestController $controller */
Yii::$app->request->headers->set('X-Api-Key', 'user1');
$controller = Yii::$app->createController('test')[0];
$this->assertEquals('success', $controller->run('test/d'));
}
@ -117,6 +140,7 @@ class CompositeAuthTest extends \yiiunit\TestCase
public function testRunAction()
{
/** @var TestController $controller */
Yii::$app->request->headers->set('X-Api-Key', 'user1');
$controller = Yii::$app->createController('test')[0];
$this->assertEquals('success', $controller->run('b'));
}
@ -124,22 +148,123 @@ class CompositeAuthTest extends \yiiunit\TestCase
public function testRunButWithActionIdOnly()
{
/** @var TestController $controller */
Yii::$app->request->headers->set('X-Api-Key', 'user1');
$controller = Yii::$app->createController('test')[0];
$this->assertEquals('success', $controller->run('c'));
}
public function testCompositeAuth()
public function testRunWithWrongToken()
{
Yii::$app->request->headers->set('Authorization', base64_encode("foo:bar"));
/** @var TestAuthController $controller */
/** @var TestController $controller */
Yii::$app->request->headers->set('X-Api-Key', 'wrong-user');
$controller = Yii::$app->createController('test')[0];
$controller->authMethods = [
HttpBearerAuth::className(),
TestAuth::className(),
$this->expectException('yii\web\UnauthorizedHttpException');
$controller->run('a');
}
public function testRunWithoutAuthHeader()
{
/** @var TestController $controller */
$controller = Yii::$app->createController('test')[0];
$this->expectException('yii\web\UnauthorizedHttpException');
$controller->run('a');
}
public function testRunWithOptionalAction()
{
/** @var TestController $controller */
$controller = Yii::$app->createController('test')[0];
$controller->optional = ['a'];
$this->assertEquals('success', $controller->run('a'));
}
public function compositeAuthDataProvider()
{
return [
//base usage
[
[
HttpBearerAuth::className(),
TestAuth::className(),
],
'b',
true
],
//empty auth methods
[
[],
'b',
true
],
//only "a", run "b"
[
[
HttpBearerAuth::className(),
[
'class' => TestAuth::className(),
'only' => ['a']
],
],
'b',
false
],
//only "a", run "a"
[
[
HttpBearerAuth::className(),
[
'class' => TestAuth::className(),
'only' => ['a']
],
],
'a',
true
],
//except "b", run "a"
[
[
HttpBearerAuth::className(),
[
'class' => TestAuth::className(),
'except' => ['b']
],
],
'a',
true
],
//except "b", run "b"
[
[
HttpBearerAuth::className(),
[
'class' => TestAuth::className(),
'except' => ['b']
],
],
'b',
false
]
];
try {
$this->assertEquals('success', $controller->run('b'));
} catch (UnauthorizedHttpException $e) {
}
/**
* @param array $authMethods
* @param string $actionId
* @param bool $expectedAuth
*
* @dataProvider compositeAuthDataProvider
*/
public function testCompositeAuth($authMethods, $actionId, $expectedAuth)
{
Yii::$app->request->headers->set('X-Api-Key', 'user1');
/** @var TestController $controller */
$controller = Yii::$app->createController('test')[0];
$controller->authMethods = $authMethods;
if( $expectedAuth)
$this->assertEquals('success', $controller->run($actionId));
else {
$this->expectException('yii\web\UnauthorizedHttpException');
$controller->run($actionId);
}
}
}