Skip to content

Commit

Permalink
feat: [Admin] user impersonation
Browse files Browse the repository at this point in the history
  • Loading branch information
kumy committed Sep 1, 2024
1 parent 6e4466a commit 025cb2d
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 3 deletions.
2 changes: 2 additions & 0 deletions docker-compose.local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ x-variables: &variables

GK_SESSION_IN_REDIS: "true"

GK_SITE_ADMINISTRATORS: "1"

services:

adminer:
Expand Down
100 changes: 100 additions & 0 deletions tests-qa/acceptance/120_admin/10_impersonation.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
*** Settings ***
Resource ../ressources/Authentication.robot
Resource ../ressources/vars/Urls.robot
Resource ../ressources/Moves.robot
Variables ../ressources/vars/users.yml
Variables ../ressources/vars/geokrety.yml
Variables ../ressources/vars/waypoints.yml
Suite Setup Suite Setup

*** Variables ***

${PERCENT} = %25

*** Test Cases ***

Anonymous users cannot impersonate
Go To Url ${PAGE_HOME_URL_EN}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Go To Url ${PAGE_USER_3_PROFILE_URL}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Go To Url ${PAGE_ADMIN_IMPERSONATE_USER_START} userid=${USER_3.id} redirect=${PAGE_SIGN_IN_URL}
Go To Url ${PAGE_ADMIN_IMPERSONATE_USER_STOP} userid=${USER_3.id} redirect=${PAGE_SIGN_IN_URL}


Other users cannot impersonate
Sign In ${USER_2.name} Fast

Go To Url ${PAGE_HOME_URL_EN}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Go To Url ${PAGE_USER_3_PROFILE_URL}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Go To Url ${PAGE_ADMIN_IMPERSONATE_USER_START} userid=${USER_3.id} redirect=${PAGE_HOME_URL_EN}
Page Should Contain HTTP 403
Go To Url ${PAGE_ADMIN_IMPERSONATE_USER_STOP} userid=${USER_3.id} redirect=${PAGE_HOME_URL_EN}
Page Should Contain HTTP 403


Admin users can impersonate
Sign In ${USER_1.name} Fast

Go To Url ${PAGE_HOME_URL_EN}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Go To Url ${PAGE_USER_1_PROFILE_URL}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Go To Url ${PAGE_USER_3_PROFILE_URL}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}
Element Text Should Be ${NAVBAR_PROFILE_LINK} ${USER_1.name}

Go To Url ${PAGE_ADMIN_IMPERSONATE_USER_START} userid=${USER_3.id} redirect=${PAGE_USER_3_PROFILE_URL}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}
Element Text Should Be ${NAVBAR_PROFILE_LINK} ${USER_3.name}

Go To Url ${PAGE_HOME_URL_EN}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Go To Url ${PAGE_USER_1_PROFILE_URL}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Go To Url ${PAGE_USER_2_PROFILE_URL}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Click Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Element Text Should Be ${NAVBAR_PROFILE_LINK} ${USER_2.name}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Go To Url ${PAGE_USER_3_PROFILE_URL}
Element Text Should Be ${NAVBAR_PROFILE_LINK} ${USER_2.name}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

Click Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}
Location Should Be ${PAGE_USER_2_PROFILE_URL}
Element Text Should Be ${NAVBAR_PROFILE_LINK} ${USER_1.name}
Page Should Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK}
Page Should Not Contain Element ${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK}

*** Keywords ***

Suite Setup
Clear Database And Seed ${3} users
Seed ${1} geokrety owned by ${1}
Sign Out Fast
2 changes: 2 additions & 0 deletions tests-qa/acceptance/ressources/ComponentsLocator.robot
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ ${NAVBAR_ACTIONS_CREATE_GEOKRET_LINK} //*[@id="navbar-actions-create"]
${NAVBAR_ACTIONS_CLAIM_GEOKRET_LINK} //*[@id="navbar-actions-claim"]
${NAVBAR_ACTIONS_SEARCH_LINK} //*[@id="navbar-actions-search"]
${NAVBAR_ACTIONS_PHOTO_GALLERY_LINK} //*[@id="navbar-actions-gallery"]
${NAVBAR_ACTIONS_IMPERSONATE_USER_START_LINK} //*[@id="navbar-impersonate-start"]
${NAVBAR_ACTIONS_IMPERSONATE_USER_STOP_LINK} //*[@id="navbar-impersonate-stop"]


################
Expand Down
7 changes: 7 additions & 0 deletions tests-qa/acceptance/ressources/vars/Urls.robot
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ ${PAGE_LEGACY_API_EXPORT_URL} ${GK_URL}/api/v1/export
${PAGE_LEGACY_API_EXPORT2_URL} ${GK_URL}/api/v1/export2
${PAGE_LEGACY_API_EXPORT_OC_URL} ${GK_URL}/api/v1/export_oc

# ADMIN
${PAGE_ADMIN_HOME} ${PAGE_HOME_URL}/admin

# IMPERSONATION
${PAGE_ADMIN_IMPERSONATE_USER_START} ${PAGE_ADMIN_HOME}/impersonate/\${params.userid}/start
${PAGE_ADMIN_IMPERSONATE_USER_STOP} ${PAGE_ADMIN_HOME}/impersonate/stop

*** Keywords ***

Go To Url
Expand Down
11 changes: 10 additions & 1 deletion website/app-templates/smarty/navbar-profile.tpl
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
{if $f3->get('SESSION.IS_LOGGED_IN') && !is_null($current_user)}

{if $f3->get('SESSION.IS_ADMIN')}
<li><a id="navbar-profile-admin" href="{'admin_home'|alias}">{fa icon="support"} {t}Admin{/t}</a></li>
<li><a id="navbar-profile-admin" href="{'admin_home'|alias}" class="navbar-admin">{fa icon="support"} {t}Admin{/t}</a></li>
{if $f3->get('SESSION.ADMIN_ID') }
{if isset($user) && $user->id !== $f3->get('SESSION.CURRENT_USER')}
<li><a id="navbar-impersonate-start" href="{'admin_impersonate_user'|alias:sprintf('userid=%d', $user->id)}" title="Impersonate {$user->username} account" class="navbar-admin">{fa icon="user-secret"}</a></li>
{/if}
{if $f3->get('SESSION.ADMIN_IMPERSONATING') === true}
<li><a id="navbar-impersonate-stop" href="{'admin_impersonate_user_stop'|alias}" title="Stop impersonating {$f3->get('SESSION.CURRENT_USERNAME')} account" class="navbar-admin">{fa icon="user-times"}</a></li>
{/if}
{/if}
{/if}
<li>
<a id="navbar-profile-profile" href="{'user_details'|alias:sprintf('userid=%d', $f3->get('SESSION.CURRENT_USER'))}">
Expand Down
36 changes: 36 additions & 0 deletions website/app/GeoKrety/Controller/Admin/Impersonate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace GeoKrety\Controller\Admin;

use GeoKrety\Controller\Admin\Traits\CurrentAdminLoader;
use GeoKrety\Controller\Base;
use GeoKrety\Model\User;

class Impersonate extends Base {
use CurrentAdminLoader;

public function get(\Base $f3) {
$user = new User();
$user->load(['id = ?', $f3->get('PARAMS.userid')]);
if ($user->dry()) {
$f3->error(404, _('This user does not exist.'));
}

$f3->set('CURRENT_USER', $user->id);
$f3->set('SESSION.CURRENT_USER', $user->id);
$f3->set('SESSION.CURRENT_USERNAME', $user->username);
$f3->set('SESSION.ADMIN_IMPERSONATING', true);

$f3->reroute(['user_details', ['userid' => $user->id]]);
}

public function stop(\Base $f3) {
$user_id = $f3->get('CURRENT_USER');
$f3->set('CURRENT_USER', $this->currentAdmin->id);
$f3->set('SESSION.CURRENT_USER', $this->currentAdmin->id);
$f3->set('SESSION.CURRENT_USERNAME', $this->currentAdmin->username);
$f3->clear('SESSION.ADMIN_IMPERSONATING');

$f3->reroute(['user_details', ['userid' => $user_id]]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace GeoKrety\Controller\Admin\Traits;

use GeoKrety\Model\User;
use GeoKrety\Service\Smarty;

/**
* Load the currently connected admin into `currentAdmin` variable in php and smarty.
*/
trait CurrentAdminLoader {
protected User $currentAdmin;

public function beforeRoute(\Base $f3) {
parent::beforeRoute($f3);

if (!$f3->get('SESSION.IS_LOGGED_IN')) {
$f3->error(401);
}

$user = new User();
$user->load(['id = ?', $f3->get('SESSION.ADMIN_ID')]);
if ($user->dry()) {
$f3->error(404, _('This user does not exist.'));
}
$this->currentAdmin = $user;
Smarty::assign('currentAdmin', $this->currentAdmin);

if (method_exists($this, '_beforeRoute')) {
$this->_beforeRoute($f3);
}
}
}
1 change: 1 addition & 0 deletions website/app/GeoKrety/Controller/Pages/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ abstract class Base {
'devel_mail',
'devel_mail_delete',
'devel_mail_delete_all',
'admin_impersonate_user_stop',
];

protected ?User $current_user = null;
Expand Down
2 changes: 2 additions & 0 deletions website/app/GeoKrety/Controller/Pages/Login.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,11 @@ public static function connectUser(\Base $f3, User $user, ?string $method = null
if (in_array($user->id, GK_SITE_ADMINISTRATORS)) {
$f3->set('SESSION.user.group', AuthGroup::AUTH_LEVEL_ADMINISTRATORS);
$f3->set('SESSION.IS_ADMIN', true);
$f3->set('SESSION.ADMIN_ID', $user->id);
} else {
$f3->set('SESSION.user.group', AuthGroup::AUTH_LEVEL_AUTHENTICATED);
$f3->set('SESSION.IS_ADMIN', false);
$f3->clear('SESSION.ADMIN_ID');
}
Smarty::assign('current_user', $user);
Event::instance()->emit("user.login.$method-effective", $user);
Expand Down
3 changes: 3 additions & 0 deletions website/app/admin.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ GET @admin_news_list: /admin/news = \GeoKrety\Controller\Admin\NewsList->get
GET @admin_news_list_paginate: /admin/news/page/@page = \GeoKrety\Controller\Admin\NewsList->get
GET @admin_news_view: /admin/news/@newsid = \GeoKrety\Controller\Admin\NewsView->get

GET @admin_impersonate_user: /admin/impersonate/@userid/start = \GeoKrety\Controller\Admin\Impersonate->get
GET @admin_impersonate_user_stop: /admin/impersonate/stop = \GeoKrety\Controller\Admin\Impersonate->stop

; statistics
GET @statistics_waypoints_restart: /admin/statistics/waypoints/@service_id/restart = \GeoKrety\Controller\Statistics->force_complete_synchronization

Expand Down
4 changes: 2 additions & 2 deletions website/public/app-ui/css/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
border: 0;
}

#navbar-profile-admin {
color: orangered;
.navbar-admin {
color: orangered !important;
}

.leaflet-container {
Expand Down

0 comments on commit 025cb2d

Please sign in to comment.