From 8e663365fa59154ef3ae425e25e6e2e0dd68f6b9 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Thu, 26 Aug 2021 15:09:23 -0600 Subject: [PATCH] Backport 1.1 security fixes --- modules/backend/models/User.php | 66 ++++++++++++++++++++++++++++++++- modules/cms/models/ThemeLog.php | 2 +- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/modules/backend/models/User.php b/modules/backend/models/User.php index 90dd059bd9..b04d681594 100644 --- a/modules/backend/models/User.php +++ b/modules/backend/models/User.php @@ -27,8 +27,8 @@ class User extends UserBase public $rules = [ 'email' => 'required|between:6,255|email|unique:backend_users', 'login' => 'required|between:2,255|unique:backend_users', - 'password' => 'required:create|between:4,255|confirmed', - 'password_confirmation' => 'required_with:password|between:4,255' + 'password' => 'required:create|min:4|confirmed', + 'password_confirmation' => 'required_with:password|min:4' ]; /** @@ -209,4 +209,66 @@ public function unsuspend() { BackendAuth::findThrottleByUserId($this->id)->unsuspend(); } + + // + // Impersonation + // + + /** + * Returns an array of merged permissions based on the user's individual permissions + * and their group permissions filtering out any permissions the impersonator doesn't + * have access to (if the current user is being impersonated) + * + * @return array + */ + public function getMergedPermissions() + { + if (!$this->mergedPermissions) { + $permissions = parent::getMergedPermissions(); + + // If the user is being impersonated filter out any permissions the impersonator doesn't have access to already + if (BackendAuth::isImpersonator()) { + $impersonator = BackendAuth::getImpersonator(); + if ($impersonator && $impersonator !== $this) { + foreach ($permissions as $i => $permission) { + if (!$impersonator->hasAccess($permission)) { + unset($permissions[$i]); + } + } + $this->mergedPermissions = $permissions; + } + } + } + + return $this->mergedPermissions; + } + + /** + * Check if this user can be impersonated by the provided impersonator + * Super users cannot be impersonated and all users cannot be impersonated unless there is an impersonator + * present and the impersonator has access to `backend.impersonate_users`, and the impersonator is not the + * user being impersonated + * + * @param \Winter\Storm\Auth\Models\User|false $impersonator The user attempting to impersonate this user, false when not available + * @return boolean + */ + public function canBeImpersonated($impersonator = false) + { + if ( + $this->isSuperUser() || + !$impersonator || + !($impersonator instanceof static) || + !$impersonator->hasAccess('backend.impersonate_users') || + $impersonator === $this + ) { + return false; + } + + // Clear the merged permissions before the impersonation starts + // so that they are correct even if they had been loaded prior + // to the impersonation starting + $this->mergedPermissions = null; + + return true; + } } diff --git a/modules/cms/models/ThemeLog.php b/modules/cms/models/ThemeLog.php index b725715b33..5a34515ff2 100644 --- a/modules/cms/models/ThemeLog.php +++ b/modules/cms/models/ThemeLog.php @@ -87,7 +87,7 @@ public static function add(HalcyonModel $template, $type = null) $record->content = $isDelete ? '' : $newContent; $record->old_content = $oldContent; - if ($user = BackendAuth::getUser()) { + if ($user = BackendAuth::getRealUser()) { $record->user_id = $user->id; }