Skip to content

Commit

Permalink
Configure forms access restrictions
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienClairembault committed May 7, 2024
1 parent e4d8778 commit 7c7dfa6
Show file tree
Hide file tree
Showing 38 changed files with 4,210 additions and 14 deletions.
82 changes: 82 additions & 0 deletions ajax/form/access_control.form.php
@@ -0,0 +1,82 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

include('../../inc/includes.php');

use Glpi\Form\AccessControl\FormAccessControl;

/**
* Ajax endpoint to update an access control item.
*
* This endpoint is called once per possible access control stategies when
* submitting the access control config page for a form.
*/

try {
$access_control = new FormAccessControl();

if (isset($_POST["update"])) {
// ID is mandatory
$id = $_POST['id'] ?? null;
if ($id === null) {
// Invalid request
throw new InvalidArgumentException("Missing id");
}

// Right check
$access_control->check($id, UPDATE, $_POST);

// Format user supplied config
$access_control->getFromDB($id);
$_POST['_config'] = $access_control->createConfigFromUserInput($_POST);

// Update access control item
if (!$access_control->update($_POST, true)) {
throw new RuntimeException("Failed to create destination item");
}
} else {
// Unknown request
throw new InvalidArgumentException("Unknown action");
}
} catch (\Throwable $e) {
// Log error
trigger_error(
// Insert POST data into logs to ease debugging
$e->getMessage() . ": " . json_encode($_POST),
E_USER_WARNING
);

Session::addMessageAfterRedirect(__('An unexpected error occured.'), false, ERROR);
}
44 changes: 44 additions & 0 deletions ajax/form/allowListDropdownValue.php
@@ -0,0 +1,44 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

include(__DIR__ . '../../getAbstractRightDropdownValue.php');

use Glpi\Form\AccessControl\ControlType\AllowListDropdown;
use Glpi\Form\Form;

// This dropdown is used to configure form's access controls.
// It should only be visible to users with the right to view form's access controls.
Session::checkRight(Form::$rightname, READ);
show_rights_dropdown(AllowListDropdown::class);
84 changes: 84 additions & 0 deletions ajax/form/allow_list_dropdown_count_users.php
@@ -0,0 +1,84 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

include('../../inc/includes.php');

use Glpi\Form\AccessControl\ControlType\AllowListDropdown;
use Glpi\Form\Form;

Session::checkRight(Form::$rightname, READ);

/**
* Special endpoint to preview the results of the AllowListDropdown.
*
* It will count the number ofusers that match the supplied restrictions.
* A link to the search results will also be provided if the user can read the user list.
*/


if (isset($_POST['values'])) {
$users = AllowListDropdown::getPostedIds($_POST['values'], User::class);
$groups = AllowListDropdown::getPostedIds($_POST['values'], Group::class);
$profiles = AllowListDropdown::getPostedIds($_POST['values'], Profile::class);
$empty_criteria = false;
} else {
// If the dropdown has no selected value, $_POST['values'] is not defined at all.
// This mean there are no criteria and no users should be found.
$users = [-1];
$groups = [-1];
$profiles = [-1];
$empty_criteria = true;
}

$data = AllowListDropdown::countUsersForCriteria(
$users,
$groups,
$profiles
);

// Do not display the link if there are no criteria, as the search would be confusing
// with the '-1' criteria.
if ($empty_criteria) {
unset($data['link']);
}

// Do not display the link if the user does not have the right to read the user list
if (!Session::haveRight(User::$rightname, READ)) {
unset($data['link']);
}

// Content will be rendered as JSON to allow the calling script to render it as it wishes.
header('Content-Type: application/json');
echo json_encode($data);
24 changes: 19 additions & 5 deletions front/form/form_renderer.php
Expand Up @@ -33,19 +33,25 @@
* ---------------------------------------------------------------------
*/

use Glpi\Form\AccessControl\FormAccessControlManager;
use Glpi\Form\AccessControl\FormAccessParameters;
use Glpi\Form\Form;
use Glpi\Form\Renderer\FormRenderer;
use Glpi\Http\Firewall;
use Glpi\Http\Response;

/** @var array $CFG_GLPI */

// Since forms may be available to unauthenticated users, we trust the
// `canAnswerForm` method to do the required session checks.
$SECURITY_STRATEGY = 'no_check';

include('../../inc/includes.php');

/**
* Endpoint used to display or preview a form.
*/

// For now form rendering is only used to preview a form by a technician
Session::checkRight(Form::$rightname, READ);

// Mandatory parameter: id of the form to render
$id = $_GET['id'] ?? 0;
if (!$id) {
Expand All @@ -58,8 +64,16 @@
Response::sendError(404, __("Form not found"));
}

// TODO: if displaying a form, check form access configuration (not yet implemented)
// TODO: if previewing a form, check view rights on forms
$manager = FormAccessControlManager::getInstance();

// Validate form access
$parameters = new FormAccessParameters(
session_info: Session::getCurrentSessionInfo(),
url_parameters: $_GET
);
if (!$manager->canAnswerForm($form, $parameters)) {
Response::sendError(403, __("You are not allowed to answer this form."));
}

// Render the requested form
Html::header(
Expand Down
7 changes: 4 additions & 3 deletions inc/relation.constant.php
Expand Up @@ -699,9 +699,10 @@
],

'glpi_forms_forms' => [
"_glpi_forms_answerssets" => "forms_forms_id",
"_glpi_forms_destinations_formdestinations" => "forms_forms_id",
"_glpi_forms_sections" => "forms_forms_id",
"_glpi_forms_accesscontrols_formaccesscontrols" => "forms_forms_id",
"_glpi_forms_answerssets" => "forms_forms_id",
"_glpi_forms_destinations_formdestinations" => "forms_forms_id",
"_glpi_forms_sections" => "forms_forms_id",
],

'glpi_forms_sections' => [
Expand Down
14 changes: 14 additions & 0 deletions install/migrations/update_10.0.x_to_11.0.0/form.php
Expand Up @@ -151,6 +151,20 @@
) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"
);
}
if (!$DB->tableExists('glpi_forms_accesscontrols_formaccesscontrols')) {
$DB->doQueryOrDie(
"CREATE TABLE `glpi_forms_accesscontrols_formaccesscontrols` (
`id` int {$default_key_sign} NOT NULL AUTO_INCREMENT,
`forms_forms_id` int {$default_key_sign} NOT NULL DEFAULT '0',
`strategy` varchar(255) NOT NULL,
`config` JSON NOT NULL,
`is_active` tinyint NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `unicity` (`forms_forms_id`, `strategy`),
KEY `is_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"
);
}

// Add rights for the forms object
$migration->addRight("form", ALLSTANDARDRIGHT, ['config' => UPDATE]);
Expand Down
12 changes: 12 additions & 0 deletions install/mysql/glpi-empty.sql
Expand Up @@ -9541,6 +9541,18 @@ CREATE TABLE `glpi_forms_destinations_formdestinations` (
KEY `forms_forms_id` (`forms_forms_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;

DROP TABLE IF EXISTS `glpi_forms_accesscontrols_formaccesscontrols`;
CREATE TABLE `glpi_forms_accesscontrols_formaccesscontrols` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`forms_forms_id` int unsigned NOT NULL DEFAULT '0',
`strategy` varchar(255) NOT NULL,
`config` JSON NOT NULL,
`is_active` tinyint NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `unicity` (`forms_forms_id`, `strategy`),
KEY `is_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;

DROP TABLE IF EXISTS `glpi_items_ticketrecurrents`;
CREATE TABLE `glpi_items_ticketrecurrents` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
Expand Down
13 changes: 11 additions & 2 deletions js/common.js
Expand Up @@ -33,8 +33,9 @@

/* global bootstrap */
/* global L */
/* global glpi_html_dialog */
/* global fuzzy */
/* global glpi_html_dialog */
/* global glpi_toast_info */

var timeoutglobalvar;

Expand Down Expand Up @@ -1152,7 +1153,7 @@ $(document).ready(function() {

$(document).on('submit', 'form', (e) => {
// if the submitter has a data-block-on-unsaved attribute, do not clear the unsaved changes flag
if ($(e.originalEvent.submitter).attr('data-block-on-unsaved') === 'true') {
if (e.originalEvent && $(e.originalEvent.submitter).attr('data-block-on-unsaved') === 'true') {
return;
}
window.glpiUnsavedFormChanges = false;
Expand Down Expand Up @@ -1521,6 +1522,14 @@ $(() => {
$('.content-editable-tinymce').removeClass('simulate-focus');
}
});

// General "copy to clipboard" handler.
// TODO: refactorate existing code to use this unique handler.
$(document).on('click', '[data-glpi-clipboard-text]', function() {
const text = $(this).data('glpi-clipboard-text');
navigator.clipboard.writeText(text);
glpi_toast_info(__("Copied to clipboard"));
});
});

/**
Expand Down
1 change: 1 addition & 0 deletions src/AbstractRightsDropdown.php
Expand Up @@ -95,6 +95,7 @@ public static function show(string $name, array $values, array $params = []): st
$params = array_merge([
'name' => $name . "[]",
'multiple' => true,
'width' => '100%',
], $params);

if ($params['multiple']) {
Expand Down
2 changes: 1 addition & 1 deletion src/Application/View/TemplateRenderer.php
Expand Up @@ -82,7 +82,7 @@ public function __construct(string $rootdir = GLPI_ROOT, string $cachedir = GLPI

$env_params = [
'debug' => $_SESSION['glpi_use_mode'] ?? null === Session::DEBUG_MODE,
'auto_reload' => GLPI_ENVIRONMENT_TYPE === GLPI::ENV_DEVELOPMENT,
'auto_reload' => GLPI_ENVIRONMENT_TYPE !== GLPI::ENV_PRODUCTION,
];

$tpl_cachedir = $cachedir . '/templates';
Expand Down

0 comments on commit 7c7dfa6

Please sign in to comment.