MDL-63401 tool_dataprivacy: Move cap checks to endpoints from API

This commit is contained in:
Andrew Nicols 2018-09-20 11:03:35 +08:00
parent 81bbf426f6
commit cbae8dcd57
5 changed files with 724 additions and 342 deletions

View file

@ -244,14 +244,6 @@ class api {
if (self::is_site_dpo($requestinguser)) {
// The user making the request is a DPO. Should be fine.
$datarequest->set('dpo', $requestinguser);
} else {
// If not a DPO, only users with the capability to make data requests for the user should be allowed.
// (e.g. users with the Parent role, etc).
if (!self::can_create_data_request_for_user($foruser)) {
$forusercontext = \context_user::instance($foruser);
throw new required_capability_exception($forusercontext,
'tool/dataprivacy:makedatarequestsforchildren', 'nopermissions', '');
}
}
}
// The user making the request.
@ -667,16 +659,31 @@ class api {
/**
* Checks whether a non-DPO user can make a data request for another user.
*
* @param int $user The user ID of the target user.
* @param int $requester The user ID of the user making the request.
* @return bool
* @throws coding_exception
* @param int $user The user ID of the target user.
* @param int $requester The user ID of the user making the request.
* @return bool
*/
public static function can_create_data_request_for_user($user, $requester = null) {
$usercontext = \context_user::instance($user);
return has_capability('tool/dataprivacy:makedatarequestsforchildren', $usercontext, $requester);
}
/**
* Require that the current user can make a data request for the specified other user.
*
* @param int $user The user ID of the target user.
* @param int $requester The user ID of the user making the request.
* @return bool
*/
public static function require_can_create_data_request_for_user($user, $requester = null) {
$usercontext = \context_user::instance($user);
require_capability('tool/dataprivacy:makedatarequestsforchildren', $usercontext, $requester);
return true;
}
/**
* Checks whether a user can download a data request.
*
@ -732,8 +739,6 @@ class api {
* @return \tool_dataprivacy\purpose.
*/
public static function create_purpose(stdClass $record) {
self::check_can_manage_data_registry();
$purpose = new purpose(0, $record);
$purpose->create();
@ -747,8 +752,6 @@ class api {
* @return \tool_dataprivacy\purpose.
*/
public static function update_purpose(stdClass $record) {
self::check_can_manage_data_registry();
if (!isset($record->sensitivedatareasons)) {
$record->sensitivedatareasons = '';
}
@ -768,8 +771,6 @@ class api {
* @return bool
*/
public static function delete_purpose($id) {
self::check_can_manage_data_registry();
$purpose = new purpose($id);
if ($purpose->is_used()) {
throw new \moodle_exception('Purpose with id ' . $id . ' can not be deleted because it is used.');
@ -783,8 +784,6 @@ class api {
* @return \tool_dataprivacy\purpose[]
*/
public static function get_purposes() {
self::check_can_manage_data_registry();
return purpose::get_records([], 'name', 'ASC');
}
@ -795,8 +794,6 @@ class api {
* @return \tool_dataprivacy\category.
*/
public static function create_category(stdClass $record) {
self::check_can_manage_data_registry();
$category = new category(0, $record);
$category->create();
@ -810,8 +807,6 @@ class api {
* @return \tool_dataprivacy\category.
*/
public static function update_category(stdClass $record) {
self::check_can_manage_data_registry();
$category = new category($record->id);
$category->from_record($record);
@ -827,8 +822,6 @@ class api {
* @return bool
*/
public static function delete_category($id) {
self::check_can_manage_data_registry();
$category = new category($id);
if ($category->is_used()) {
throw new \moodle_exception('Category with id ' . $id . ' can not be deleted because it is used.');
@ -842,8 +835,6 @@ class api {
* @return \tool_dataprivacy\category[]
*/
public static function get_categories() {
self::check_can_manage_data_registry();
return category::get_records([], 'name', 'ASC');
}
@ -854,8 +845,6 @@ class api {
* @return \tool_dataprivacy\context_instance
*/
public static function set_context_instance($record) {
self::check_can_manage_data_registry($record->contextid);
if ($instance = context_instance::get_record_by_contextid($record->contextid, false)) {
// Update.
$instance->from_record($record);
@ -882,7 +871,6 @@ class api {
* @return null
*/
public static function unset_context_instance(context_instance $instance) {
self::check_can_manage_data_registry($instance->get('contextid'));
$instance->delete();
}
@ -896,9 +884,6 @@ class api {
public static function set_contextlevel($record) {
global $DB;
// Only manager at system level can set this.
self::check_can_manage_data_registry();
if ($record->contextlevel != CONTEXT_SYSTEM && $record->contextlevel != CONTEXT_USER) {
throw new \coding_exception('Only context system and context user can set a contextlevel ' .
'purpose and retention');
@ -930,7 +915,6 @@ class api {
* @return category|false
*/
public static function get_effective_context_category(\context $context, $forcedvalue=false) {
self::check_can_manage_data_registry($context->id);
if (!data_registry::defaults_set()) {
return false;
}
@ -946,7 +930,6 @@ class api {
* @return purpose|false
*/
public static function get_effective_context_purpose(\context $context, $forcedvalue=false) {
self::check_can_manage_data_registry($context->id);
if (!data_registry::defaults_set()) {
return false;
}
@ -962,7 +945,6 @@ class api {
* @return category|false
*/
public static function get_effective_contextlevel_category($contextlevel, $forcedvalue=false) {
self::check_can_manage_data_registry(\context_system::instance()->id);
if (!data_registry::defaults_set()) {
return false;
}
@ -978,7 +960,6 @@ class api {
* @return purpose|false
*/
public static function get_effective_contextlevel_purpose($contextlevel, $forcedvalue=false) {
self::check_can_manage_data_registry(\context_system::instance()->id);
if (!data_registry::defaults_set()) {
return false;
}
@ -993,8 +974,6 @@ class api {
* @return \tool_dataprivacy\expired_context
*/
public static function create_expired_context($contextid) {
self::check_can_manage_data_registry();
$record = (object)[
'contextid' => $contextid,
'status' => expired_context::STATUS_EXPIRED,
@ -1012,8 +991,6 @@ class api {
* @return bool True on success.
*/
public static function delete_expired_context($id) {
self::check_can_manage_data_registry();
$expiredcontext = new expired_context($id);
return $expiredcontext->delete();
}
@ -1026,8 +1003,6 @@ class api {
* @return null
*/
public static function set_expired_context_status(expired_context $expiredctx, $status) {
self::check_can_manage_data_registry();
$expiredctx->set('status', $status);
$expiredctx->save();
}

View file

@ -92,17 +92,30 @@ class external extends external_api {
]);
$requestid = $params['requestid'];
// Validate context.
// Validate context and access to manage the registry.
$context = context_user::instance($USER->id);
self::validate_context($context);
// Ensure the request exists.
$select = 'id = :id AND (userid = :userid OR requestedby = :requestedby)';
$params = ['id' => $requestid, 'userid' => $USER->id, 'requestedby' => $USER->id];
$requestexists = data_request::record_exists_select($select, $params);
$requests = data_request::get_records_select($select, $params);
$requestexists = count($requests) === 1;
$result = false;
if ($requestexists) {
$request = reset($requests);
$datasubject = $request->get('userid');
if ($datasubject !== $USER->id) {
// The user is not the subject. Check that they can cancel this request.
if (!api::can_create_data_request_for_user($datasubject)) {
$forusercontext = \context_user::instance($datasubject);
throw new required_capability_exception($forusercontext,
'tool/dataprivacy:makedatarequestsforchildren', 'nopermissions', '');
}
}
// TODO: Do we want a request to be non-cancellable past a certain point? E.g. When it's already approved/processing.
$result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_CANCELLED);
} else {
@ -257,9 +270,10 @@ class external extends external_api {
]);
$requestid = $params['requestid'];
// Validate context.
// Validate context and access to manage the registry.
$context = context_system::instance();
self::validate_context($context);
api::check_can_manage_data_registry();
$message = get_string('markedcomplete', 'tool_dataprivacy');
// Update the data request record.
@ -748,7 +762,9 @@ class external extends external_api {
'jsonformdata' => $jsonformdata
]);
// Validate context and access to manage the registry.
self::validate_context(\context_system::instance());
api::check_can_manage_data_registry();
$serialiseddata = json_decode($params['jsonformdata']);
$data = array();
@ -816,6 +832,10 @@ class external extends external_api {
'id' => $id
]);
// Validate context and access to manage the registry.
self::validate_context(\context_system::instance());
api::check_can_manage_data_registry();
$result = api::delete_purpose($params['id']);
return [
@ -865,7 +885,9 @@ class external extends external_api {
'jsonformdata' => $jsonformdata
]);
// Validate context and access to manage the registry.
self::validate_context(\context_system::instance());
api::check_can_manage_data_registry();
$serialiseddata = json_decode($params['jsonformdata']);
$data = array();
@ -933,6 +955,10 @@ class external extends external_api {
'id' => $id
]);
// Validate context and access to manage the registry.
self::validate_context(\context_system::instance());
api::check_can_manage_data_registry();
$result = api::delete_category($params['id']);
return [
@ -982,8 +1008,9 @@ class external extends external_api {
'jsonformdata' => $jsonformdata
]);
// Extra permission checkings are delegated to api::set_contextlevel.
// Validate context and access to manage the registry.
self::validate_context(\context_system::instance());
api::check_can_manage_data_registry();
$serialiseddata = json_decode($params['jsonformdata']);
$data = array();
@ -1063,6 +1090,7 @@ class external extends external_api {
$customdata = \tool_dataprivacy\form\context_instance::get_context_instance_customdata($context);
$mform = new \tool_dataprivacy\form\context_instance(null, $customdata, 'post', '', null, true, $data);
if ($validateddata = $mform->get_data()) {
api::check_can_manage_data_registry($validateddata->contextid);
$context = api::set_context_instance($validateddata);
} else if ($errors = $mform->is_validated()) {
$warnings[] = json_encode($errors);
@ -1192,9 +1220,9 @@ class external extends external_api {
]);
$ids = $params['ids'];
// Validate context.
$context = context_system::instance();
self::validate_context($context);
// Validate context and access to manage the registry.
self::validate_context(\context_system::instance());
api::check_can_manage_data_registry();
$result = true;
if (!empty($ids)) {
@ -1366,6 +1394,7 @@ class external extends external_api {
$context = context_system::instance();
self::validate_context($context);
api::check_can_manage_data_registry();
$categories = api::get_categories();
$options = data_registry_page::category_options($categories, $includenotset, $includeinherit);