Browse Source

Fixes #4793: `yii\filters\AccessControl` now can be used without `user` component

tags/2.0.12
Bizley 7 years ago committed by Alexander Makarov
parent
commit
f8b3d68817
  1. 2
      framework/CHANGELOG.md
  2. 3
      framework/UPGRADE.md
  3. 13
      framework/filters/AccessControl.php
  4. 13
      framework/filters/AccessRule.php
  5. 26
      tests/framework/filters/AccessRuleTest.php

2
framework/CHANGELOG.md

@ -86,9 +86,9 @@ Yii Framework 2 Change Log
- Enh #13981: `yii\caching\Cache::getOrSet()` now supports both `Closure` and `callable` (silverfire)
- Enh #13994: Refactored `yii\filters\RateLimiter`. Added tests (vladis84)
- Enh #14059: Removed unused AR instantiating for calling of static methods (ElisDN)
- Enh #4793: `yii\filters\AccessControl` now can be used without `user` component (bizley)
- Enh: Added `yii\di\Instance::__set_state()` method to restore object after serialization using `var_export()` function (silvefire)
- Bug #14072: Fixed a bug where `\yii\db\Command::createTable()`, `addForeignKey()`, `dropForeignKey()`, `addCommentOnColumn()`, and `dropCommentFromColumn()` weren't refreshing the table cache on `yii\db\Schema` (brandonkelly)
- Bug #10305: Oracle SQL queries with `IN` condition and more than 1000 parameters are working now (silverfire)
2.0.11.2 February 08, 2017

3
framework/UPGRADE.md

@ -65,6 +65,9 @@ Upgrade from Yii 2.0.11
* The signature of `yii\cache\Cache::getOrSet()` has been adjusted to also accept a callable and not only `Closure`.
If you extend this method, make sure to adjust your code.
* `yii\filters\AccessControl` now can be used without `user` component.
In this case `yii\filters\AccessControl::denyAccess()` throws `yii\web\ForbiddenHttpException` and using `AccessRule`
matching a role throws `yii\base\InvalidConfigException`.
Upgrade from Yii 2.0.10
-----------------------

13
framework/filters/AccessControl.php

@ -57,8 +57,9 @@ use yii\web\ForbiddenHttpException;
class AccessControl extends ActionFilter
{
/**
* @var User|array|string the user object representing the authentication status or the ID of the user application component.
* @var User|array|string|false the user object representing the authentication status or the ID of the user application component.
* Starting from version 2.0.2, this can also be a configuration array for creating the object.
* Starting from version 2.0.12, you can set it to `false` to explicitly switch this component support off for the filter.
*/
public $user = 'user';
/**
@ -95,7 +96,9 @@ class AccessControl extends ActionFilter
public function init()
{
parent::init();
$this->user = Instance::ensure($this->user, User::className());
if ($this->user !== false) {
$this->user = Instance::ensure($this->user, User::className());
}
foreach ($this->rules as $i => $rule) {
if (is_array($rule)) {
$this->rules[$i] = Yii::createObject(array_merge($this->ruleConfig, $rule));
@ -140,12 +143,12 @@ class AccessControl extends ActionFilter
* Denies the access of the user.
* The default implementation will redirect the user to the login page if he is a guest;
* if the user is already logged, a 403 HTTP exception will be thrown.
* @param User $user the current user
* @throws ForbiddenHttpException if the user is already logged in.
* @param User|false $user the current user or boolean `false` in case of detached User component
* @throws ForbiddenHttpException if the user is already logged in or in case of detached User component.
*/
protected function denyAccess($user)
{
if ($user->getIsGuest()) {
if ($user !== false && $user->getIsGuest()) {
$user->loginRequired();
} else {
throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.'));

13
framework/filters/AccessRule.php

@ -9,6 +9,7 @@ namespace yii\filters;
use yii\base\Component;
use yii\base\Action;
use yii\base\InvalidConfigException;
use yii\web\User;
use yii\web\Request;
use yii\base\Controller;
@ -44,8 +45,8 @@ class AccessRule extends Component
*/
public $controllers;
/**
* @var array list of roles that this rule applies to. Two special roles are recognized, and
* they are checked via [[User::isGuest]]:
* @var array list of roles that this rule applies to (requires properly configured User component).
* Two special roles are recognized, and they are checked via [[User::isGuest]]:
*
* - `?`: matches a guest user (not authenticated yet)
* - `@`: matches an authenticated user
@ -101,9 +102,9 @@ class AccessRule extends Component
/**
* Checks whether the Web user is allowed to perform the specified action.
* @param Action $action the action to be performed
* @param User $user the user object
* @param User|false $user the user object or `false` in case of detached User component
* @param Request $request
* @return bool|null true if the user is allowed, false if the user is denied, null if the rule does not apply to the user
* @return bool|null `true` if the user is allowed, `false` if the user is denied, `null` if the rule does not apply to the user
*/
public function allows($action, $user, $request)
{
@ -141,12 +142,16 @@ class AccessRule extends Component
/**
* @param User $user the user object
* @return bool whether the rule applies to the role
* @throws InvalidConfigException if User component is detached
*/
protected function matchRole($user)
{
if (empty($this->roles)) {
return true;
}
if ($user === false) {
throw new InvalidConfigException('The user application component must be available to specify roles in AccessRule.');
}
foreach ($this->roles as $role) {
if ($role === '?') {
if ($user->getIsGuest()) {

26
tests/framework/filters/AccessRuleTest.php

@ -104,7 +104,7 @@ class AccessRuleTest extends \yiiunit\TestCase
public function testMatchAction()
{
$action = $this->mockAction();
$user = $this->mockUser();
$user = false;
$request = $this->mockRequest();
$rule = new AccessRule([
@ -180,10 +180,28 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertEquals($expected, $rule->allows($action, $user, $request));
}
/**
* Test that matching role is not possible without User component
*
* @see https://github.com/yiisoft/yii2/issues/4793
*/
public function testMatchRoleWithoutUser() {
$action = $this->mockAction();
$request = $this->mockRequest();
$rule = new AccessRule([
'allow' => true,
'roles' => ['@'],
]);
$this->expectException('yii\base\InvalidConfigException');
$rule->allows($action, false, $request);
}
public function testMatchVerb()
{
$action = $this->mockAction();
$user = $this->mockUser();
$user = false;
$rule = new AccessRule([
'allow' => true,
@ -214,7 +232,7 @@ class AccessRuleTest extends \yiiunit\TestCase
public function testMatchIP()
{
$action = $this->mockAction();
$user = $this->mockUser();
$user = false;
$request = $this->mockRequest();
$rule = new AccessRule();
@ -304,7 +322,7 @@ class AccessRuleTest extends \yiiunit\TestCase
public function testMatchIPWildcard()
{
$action = $this->mockAction();
$user = $this->mockUser();
$user = false;
$request = $this->mockRequest();
$rule = new AccessRule();

Loading…
Cancel
Save