Skip to content

Commit b02ce61

Browse files
committed
reauth on massive action actions
1 parent 8fed928 commit b02ce61

13 files changed

Lines changed: 139 additions & 24 deletions

File tree

ajax/dropdownMassiveActionAuthMethods.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,5 @@
6262
break;
6363
}
6464

65-
echo "&nbsp;<input type='submit' name='" . htmlescape($name) . "' class='btn btn-primary' value=\"" . _sx('button', 'Post') . "\">";
65+
echo "&nbsp;<input type='submit' name='" . htmlescape($name) . "' class='btn btn-primary' value=\"" . _sx('button', 'Post 1') . "\">";
6666
}

ajax/dropdownMassiveActionField.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
if (isset($_POST['inline']) && $_POST['inline']) {
5656
$inline = true;
5757
}
58-
$submitname = _sx('button', 'Post');
58+
$submitname = _sx('button', 'Post 2');
5959
if (isset($_POST['submitname']) && $_POST['submitname']) {
6060
$submitname = htmlescape($_POST['submitname']);
6161
}

ajax/massiveaction.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,15 @@
3434
*/
3535

3636
/**
37-
* @since 0.84
37+
* Display a massive action form
3838
*/
3939

4040
global $CFG_GLPI;
41+
/**
42+
* $_POST
43+
* - item
44+
* - <user_id> : <un nombre?>
45+
*/
4146

4247
header("Content-Type: text/html; charset=UTF-8");
4348
Html::header_nocache();

front/massiveaction.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
* ---------------------------------------------------------------------
3434
*/
3535

36+
use Glpi\Exception\RedirectException;
37+
use Glpi\Security\ReAuth\ReAuthManager;
38+
3639
require_once(__DIR__ . '/_check_webserver_config.php');
3740

3841
global $CFG_GLPI;
@@ -41,7 +44,17 @@
4144
Html::header_nocache();
4245

4346
try {
47+
$referer = get_item_type_from_post() ?? '/'; // page used to trigger massive action
48+
$reauth_manager = new ReAuthManager();
49+
$reauth_manager->setCancelURL($referer);
50+
$reauth_manager->checkReAuthenticationOrRedirect();
51+
4452
$ma = new MassiveAction($_POST, $_GET, 'process');
53+
$ma->setRedirect($referer);
54+
}
55+
// process redirect exceptions
56+
catch (RedirectException $e) {
57+
throw $e;
4558
} catch (Throwable $e) {
4659
Html::popHeader(__('Bulk modification error'));
4760

@@ -96,4 +109,22 @@
96109
Session::addMessageAfterRedirect($message, false, ERROR);
97110
}
98111
}
112+
99113
Html::redirect($results['redirect']);
114+
115+
function get_item_type_from_post(): ?string
116+
{
117+
global $CFG_GLPI;
118+
119+
$items = isset($_POST['items']) ? array_keys($_POST['items']) : [];
120+
if (count($items) === 1) {
121+
/** @var class-string<CommonDBTM> $item_type */
122+
$item_type = $items[0];
123+
return (new $item_type())->getRedirectToListUrl();
124+
} elseif (count($items) > 1) {
125+
// the sole item list with mixed itemtype
126+
return $CFG_GLPI["root_doc"] . '/front/allassets.php';
127+
}
128+
129+
return null;
130+
}

src/Glpi/Controller/Security/ReAuthController.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,11 @@ private function buildTemplateContext(): array
109109
}
110110

111111
return [
112-
'redirect' => $this->reAuthManager->getRedirectURL(),
113-
'action' => $this->router->generate('reauth_verify'),
114-
'label' => $this->reAuthManager->getLabel(),
115-
'template' => $this->reAuthManager->getPromptTemplate(),
112+
'redirect' => $this->reAuthManager->getRedirectURL(),
113+
'cancel_url' => $this->reAuthManager->getCancelURL(),
114+
'action' => $this->router->generate('reauth_verify'),
115+
'label' => $this->reAuthManager->getLabel(),
116+
'template' => $this->reAuthManager->getPromptTemplate(),
116117
];
117118
}
118119
}

src/Glpi/Security/ReAuth/ReAuthManager.php

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,20 @@ public function checkReAuthenticationOrRedirect(): void
6565
*/
6666
public function redirect(): never
6767
{
68-
global $CFG_GLPI;
69-
70-
$current_url = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . explode('?', $_SERVER['REQUEST_URI'])[0];
68+
$this->setRedirect();
69+
throw new RedirectException('/ReAuth/Prompt');
70+
}
7171

72-
$this->setRedirectURL($current_url);
73-
$this->setRedirectMethod($_SERVER['REQUEST_METHOD'] === 'POST' ? 'POST' : 'GET');
74-
$this->setRedirectData($_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET);
72+
public function getButtonToReauthPrompt(): string
73+
{
74+
$this->setRedirect();
7575

76-
throw new RedirectException('/ReAuth/Prompt');
76+
return '<a href="ReAuth/Prompt">Reauth</a>'; // @todo manque la base_url + sprintf avec i18n
7777
}
7878

79+
/**
80+
* User has a valid reauth session
81+
*/
7982
public function isReAuthenticated(): bool
8083
{
8184
$current_limit_timestamp = $_SESSION['glpi_reauth_until'] ?? null;
@@ -118,6 +121,11 @@ public function getRedirectURL(): string
118121
return $_SESSION['glpi_reauth_redirect'] ?? '/';
119122
}
120123

124+
public function getCancelURL(): string
125+
{
126+
return $_SESSION['glpi_reauth_cancel_url'] ?? $this->getRedirectURL();
127+
}
128+
121129
/** @return array<string, string> */
122130
public function getRedirectData(): array
123131
{
@@ -132,6 +140,20 @@ public function getRedirectMethod(): string
132140
return $_SESSION['glpi_reauth_httpmethod'] ?? 'GET';
133141
}
134142

143+
public function setCancelURL(string $url): void
144+
{
145+
$_SESSION['glpi_reauth_cancel_url'] = $url;
146+
}
147+
148+
private function setRedirect(): void
149+
{
150+
$current_url = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . explode('?', $_SERVER['REQUEST_URI'])[0];
151+
152+
$this->setRedirectURL($current_url);
153+
$this->setRedirectMethod($_SERVER['REQUEST_METHOD'] === 'POST' ? 'POST' : 'GET');
154+
$this->setRedirectData($_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET);
155+
}
156+
135157
private function getStrategy(): ReAuthStrategyInterface
136158
{
137159
if ($this->strategy === null) {

src/Html.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,7 @@ public static function getOpenMassiveActionsForm($name = '')
19791979
* - tag_to_send : the tag of the elements to send to the ajax window (default: common)
19801980
* - action_button_classes : string of classes to add to the action button
19811981
* - display : display or return the generated html (default true)
1982+
* - reauth_needed : a user reauth is required @todo revert
19821983
*
19831984
* @return bool|string the html if display parameter is false, or true
19841985
**/
@@ -1988,6 +1989,7 @@ public static function showMassiveActions($options = [])
19881989

19891990
/// TODO : permit to pass several itemtypes to show possible actions of all types : need to clean visibility management after
19901991

1992+
// default values, if not set in $options
19911993
$p['ontop'] = true;
19921994
$p['num_displayed'] = -1;
19931995
$p['forcecreate'] = false;
@@ -2008,12 +2010,14 @@ public static function showMassiveActions($options = [])
20082010
$p['tag_to_send'] = 'common';
20092011
$p['action_button_classes'] = 'btn btn-sm btn-primary me-2';
20102012
$p['display'] = true;
2013+
$p['reauth_needed'] = false;
20112014

20122015
foreach ($options as $key => $val) {
20132016
if (isset($p[$key])) {
20142017
$p[$key] = $val;
20152018
}
20162019
}
2020+
unset($options);
20172021

20182022
$url = $CFG_GLPI['root_doc'] . "/ajax/massiveaction.php";
20192023
if ($p['container']) {
@@ -2053,6 +2057,7 @@ public static function showMassiveActions($options = [])
20532057
&& ($max > 0)
20542058
&& ($max < ($p['num_displayed'] + 10))
20552059
) {
2060+
// error : too much checkbox checked, too much items to process
20562061
if (
20572062
!$p['ontop']
20582063
|| (isset($p['forcecreate']) && $p['forcecreate'])
@@ -2068,8 +2073,30 @@ public static function showMassiveActions($options = [])
20682073
);
20692074
}
20702075
}
2071-
} else {
2076+
}
2077+
else
2078+
{
2079+
// @todo revert
2080+
// Reauth is needed : "Actions" button will trigger redirection to ReAuth/Prompt page instead of opening massive action modal
2081+
// if($p['reauth_needed'] === true) {
2082+
// $out = '<a role="button" class="'. htmlescape($p['action_button_classes']) . '" href="/ReAuth/Prompt" >Reauth</a>';
2083+
// // normalement : passer par reauthManager::redirect()
2084+
// // @todo i18n
2085+
// // @todo laisser le même libélé pour ne pas perturber les utilisateurs
2086+
// // @todo manque le ~glpi_rootdoc
2087+
// // path: "/ReAuth/Prompt",
2088+
// // name: "reauth_prompt",
2089+
// if ($p['display']) {
2090+
// echo $out;
2091+
// return true; // @todo false ??
2092+
// } else {
2093+
// return $out;
2094+
// }
2095+
// }
2096+
20722097
// Create Modal window on top
2098+
2099+
20732100
if (
20742101
$p['ontop']
20752102
|| (isset($p['forcecreate']) && $p['forcecreate'])
@@ -2188,6 +2215,7 @@ public static function showDateField($name, $options = [])
21882215
'on_change' => '',
21892216
];
21902217

2218+
// replace $p values with value from $option
21912219
foreach ($options as $key => $val) {
21922220
if (isset($p[$key])) {
21932221
$p[$key] = $val;

src/MassiveAction.php

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class MassiveAction
8080

8181
/**
8282
* Class used to process current action.
83+
* @var class-string|null
8384
*/
8485
private string $processor;
8586

@@ -819,7 +820,7 @@ public function showSubForm()
819820
**/
820821
public function showDefaultSubForm()
821822
{
822-
echo Html::submit(_x('button', 'Post'), [
823+
echo Html::submit(_x('button', 'Post 3'), [
823824
'name' => 'massiveaction',
824825
'icon' => 'ti ti-device-floppy',
825826
'class' => 'btn btn-sm btn-primary',
@@ -852,6 +853,7 @@ public static function showMassiveActionsSubForm(MassiveAction $ma)
852853
]);
853854
echo '<br>';
854855
echo Html::submit(_x('button', 'Post'), [
856+
echo Html::submit(_x('button', 'Post 4'), [
855857
'name' => 'massiveaction',
856858
]);
857859
return true;
@@ -1068,7 +1070,19 @@ public static function showMassiveActionsSubForm(MassiveAction $ma)
10681070
"infocom" => UPDATE,
10691071
]);
10701072
} else {
1071-
$so_item->checkGlobal(UPDATE);
1073+
// redirect to reauth if needed // @todo cleanup
1074+
// pas possible de faire redirection ici, c'est géré en ajax : pas d'effet
1075+
// mais on peut afficher un bouton vers la reauth et on redirige vers la page actuelle
1076+
$reauth_needed = null;
1077+
$allowed = $so_item->canGlobal(UPDATE, $reauth_needed); // @todo juste update ? action delete/purge/etc
1078+
if (!$allowed && !$reauth_needed) {
1079+
// just to throw the redirect Exception, maybe we can refactor
1080+
// maybe we can refactor \CommonDBTM::checkGlobal to call \CommonDBTM::throwAccessDeniedException.
1081+
// then we can just call this method here instead of checkGlobal()
1082+
$so_item->checkGlobal(UPDATE);
1083+
}
1084+
// continue event if not currently authorized, to show the submit button
1085+
// right check (and reauth redirection) will be process on form submission
10721086
}
10731087

10741088
$itemtype_search_options = SearchOption::getOptionsForItemtype($so_itemtype);
@@ -1160,7 +1174,7 @@ public static function showMassiveActionsSubForm(MassiveAction $ma)
11601174
if (isset($ma->POST['submitname']) && $ma->POST['submitname']) {
11611175
$submitname = $ma->POST['submitname'];
11621176
} else {
1163-
$submitname = _x('button', 'Post');
1177+
$submitname = _x('button', 'Post 5');
11641178
$submit_options['icon'] = 'ti ti-device-floppy';
11651179
}
11661180
echo Html::submit($submitname, $submit_options);
@@ -1192,7 +1206,7 @@ public static function showMassiveActionsSubForm(MassiveAction $ma)
11921206
if (isset($ma->POST['submitname']) && $ma->POST['submitname']) {
11931207
$submitname = $ma->POST['submitname'];
11941208
} else {
1195-
$submitname = _x('button', 'Post');
1209+
$submitname = _x('button', 'Post 6');
11961210
$submit_options['icon'] = 'ti ti-device-floppy';
11971211
}
11981212
echo Html::submit($submitname, $submit_options);
@@ -1218,7 +1232,7 @@ public static function showMassiveActionsSubForm(MassiveAction $ma)
12181232
if (isset($ma->POST['submitname']) && $ma->POST['submitname']) {
12191233
$submitname = $ma->POST['submitname'];
12201234
} else {
1221-
$submitname = _x('button', 'Post');
1235+
$submitname = _x('button', 'Post 7');
12221236
$submit_options['icon'] = 'ti ti-device-floppy';
12231237
}
12241238
echo Html::submit($submitname, $submit_options);

src/User.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3145,7 +3145,9 @@ public static function processMassiveActionsForOneItemtype(
31453145
case 'force_user_ldap_update':
31463146
case 'clean_ldap_fields':
31473147
foreach ($ids as $id) {
3148-
if ($item->can($id, UPDATE)) {
3148+
3149+
$reauth_needed = null;
3150+
if ($item->can($id, UPDATE, reauth_needed: $reauth_needed)) {
31493151
if (
31503152
$item instanceof User
31513153
&& (
@@ -3164,6 +3166,10 @@ public static function processMassiveActionsForOneItemtype(
31643166
$ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION));
31653167
}
31663168
} else {
3169+
if ($reauth_needed) {
3170+
self::redirectToReauthPrompt();
3171+
}
3172+
31673173
$ma->itemDone($item::class, $id, MassiveAction::ACTION_NORIGHT);
31683174
$ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
31693175
}

templates/components/form/buttons.html.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373

7474
{% set reauth_needed = null %}
7575
{% set _canedit = canedit and item.can(id, constant('UPDATE'), {}, reauth_needed) %}
76+
{# @todo autre droits que UPDATE traiter #}
7677
{% if canedit or reauth_needed %}
7778
<button
7879
class="btn btn-primary me-2"

0 commit comments

Comments
 (0)