Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce allowImpersonateForRoles and denyImpersonateIntoRoles #1014

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ class Module extends BaseModule
/** @var bool Enable the 'impersonate as another user' function */
public $enableImpersonateUser = true;

/** @var array which roles are allowed to impersonate into another user? */
public $allowImpersonateForRoles = ['admin'];

/** @var array which roles are never allowed to be impersonated into? */
public $denyImpersonateIntoRoles = ['admin'];

/** @var int Email changing strategy. */
public $emailChangeStrategy = self::STRATEGY_DEFAULT;

Expand Down
48 changes: 41 additions & 7 deletions controllers/AdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -332,20 +332,17 @@ public function actionInfo($id)
*/
public function actionSwitch($id = null)
{
if (!$this->module->enableImpersonateUser) {
throw new ForbiddenHttpException(Yii::t('user', 'Impersonate user is disabled in the application configuration'));
}

if(!$id && Yii::$app->session->has(self::ORIGINAL_USER_SESSION_KEY)) {
if (!$id && Yii::$app->session->has(self::ORIGINAL_USER_SESSION_KEY)) { // Logout of impersonation
$user = $this->findModel(Yii::$app->session->get(self::ORIGINAL_USER_SESSION_KEY));

Yii::$app->session->remove(self::ORIGINAL_USER_SESSION_KEY);
} else {
if (!Yii::$app->user->identity->isAdmin) {
$user = $this->findModel($id);

if (!self::impersonationIsAllowed(Yii::$app->user, $user)) {
throw new ForbiddenHttpException;
}

$user = $this->findModel($id);
Yii::$app->session->set(self::ORIGINAL_USER_SESSION_KEY, Yii::$app->user->id);
}

Expand All @@ -360,6 +357,43 @@ public function actionSwitch($id = null)
return $this->goHome();
}

/**
* The impersonation is only allowed for all roles in $allowImpersonationForRoles and
* is always denied if the target user has one of the roles listed in $denyImpersonationIntoRoles.
*
* It is also denied if we are already impersonated into someone else.
*
* @param $user the user that wants to impersonate (usually Yii::$app->user)
* @param $target_user the target user that we want to impersonate into
* @return bool
*/
public static function impersonationIsAllowed($user, $target_user)
{
$module = Yii::$app->getModule('user');

if (!$module->enableImpersonateUser
|| Yii::$app->session->has(self::ORIGINAL_USER_SESSION_KEY)
|| $user->id == $target_user->id) {
return false;
}

$auth = Yii::$app->authManager;

foreach (Yii::$app->getModule('user')->denyImpersonateIntoRoles as $denied_role) {
if ($auth->checkAccess($target_user->id, $denied_role)) {
return false;
}
}

foreach (Yii::$app->getModule('user')->allowImpersonateForRoles as $allowed_role) {
if ($user->can($allowed_role)) {
return true;
}
}

return false;
}

/**
* If "dektrium/yii2-rbac" extension is installed, this page displays form
* where user can assign multiple auth items to user.
Expand Down
4 changes: 2 additions & 2 deletions views/admin/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@
'template' => '{switch} {resend_password} {update} {delete}',
'buttons' => [
'resend_password' => function ($url, $model, $key) {
if (\Yii::$app->user->identity->isAdmin && !$model->isAdmin) {
if (Yii::$app->user->identity->isAdmin && !$model->isAdmin) {
return '
<a data-method="POST" data-confirm="' . Yii::t('user', 'Are you sure?') . '" href="' . Url::to(['resend-password', 'id' => $model->id]) . '">
<span title="' . Yii::t('user', 'Generate and send new password to user') . '" class="glyphicon glyphicon-envelope">
</span> </a>';
}
},
'switch' => function ($url, $model) {
if(\Yii::$app->user->identity->isAdmin && $model->id != Yii::$app->user->id && Yii::$app->getModule('user')->enableImpersonateUser) {
if (AdminController::impersonationIsAllowed(Yii::$app->user, $model)) {
return Html::a('<span class="glyphicon glyphicon-user"></span>', ['/user/admin/switch', 'id' => $model->id], [
'title' => Yii::t('user', 'Become this user'),
'data-confirm' => Yii::t('user', 'Are you sure you want to switch to this user for the rest of this Session?'),
Expand Down