Skip to content

[dicom_archive/imaging_uploader] Residual fixes for advanced permissions #9761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
UPDATE permissions SET code = 'imaging_uploader_allsites', description='Imaging Scans - All Sites' WHERE code='imaging_uploader';
INSERT INTO permissions (code, description, moduleID, `action`, categoryID)

INSERT IGNORE INTO permissions (code, description, moduleID, `action`, categoryID)
SELECT 'imaging_uploader_ownsites', 'Imaging Scans - Own Sites', ID, 'View/Upload', 2 FROM modules WHERE Name='imaging_uploader';
INSERT INTO permissions (code, description, moduleID, `action`, categoryID)
INSERT IGNORE INTO permissions (code, description, moduleID, `action`, categoryID)
SELECT 'imaging_uploader_nosessionid', 'Uploads with No Session Information', ID, 'View', 2 FROM modules WHERE Name='imaging_uploader';

INSERT IGNORE INTO ConfigSettings (Name, Description, Visible, AllowMultiple, DataType, Parent, Label, OrderNumber)
Expand Down
4 changes: 2 additions & 2 deletions SQL/New_patches/2025-01-31-dicom_archive_permissions.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
INSERT INTO permissions (code, description, moduleID, `action`, categoryID)
INSERT IGNORE INTO permissions (code, description, moduleID, `action`, categoryID)
SELECT 'dicom_archive_nosessionid', 'DICOMs with no session ID', ID, 'View', 2 FROM modules WHERE Name='dicom_archive';

INSERT INTO permissions (code, description, moduleID, `action`, categoryID)
INSERT IGNORE INTO permissions (code, description, moduleID, `action`, categoryID)
SELECT 'dicom_archive_view_ownsites', 'DICOMs - Own Sites', ID, 'View', 2 FROM modules WHERE Name='dicom_archive';
2 changes: 1 addition & 1 deletion modules/dicom_archive/php/module.class.inc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class Module extends \Module
try {
$this->validateConfig();
} catch (\ConfigurationException $e) {
error_log($e);
error_log($e->getMessage());
return (new \LORIS\Middleware\PageDecorationMiddleware(
$request->getAttribute("user") ?? new \LORIS\AnonymousUser()
))->process(
Expand Down
72 changes: 70 additions & 2 deletions modules/imaging_uploader/ajax/getUploadSummary.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,90 @@
* @link https://www.github.com/Jkat/Loris-Trunk/
*/

if (!\User::singleton()->hasPermission('imaging_uploader')) {
// Base access check - user must have either of these permissions
// more access validation after request validation
if (!$user->hasAnyPermission(
[
'imaging_uploader_allsites',
'imaging_uploader_ownsites',
]
)
) {
http_response_code(403);
return;
}
$config = \NDB_Factory::singleton()->config();
$advancedperms = $config->getSetting('useAdvancedPermissions');
$user = \NDB_Factory::singleton()->user();
$centerString = implode("','", $user->getCenterIDs());
$projectString = implode("','", $user->getProjectIDs());
$username = $user->getUsername();

if (!validRequest()) {
http_response_code(400);
return;
}

$uploadId = $_POST['uploadId'];
$summary = $_POST['summary'] === 'true';
$DB = \NDB_Factory::singleton()->database();

// Access Control - mimic menu filter behaviour
// MySQL order of operations dictates that ANDs get computed before ORs which
// means this where clause can take the follwoing forms
// 1. WHERE mu.UploadedBy='$username' OR 1=1
// -> returns all records
// 2. WHERE mu.UploadedBy='$username' OR (1=1 AND s.CenterID IN ...)
// -> returns records for user's sites
// 3. WHERE mu.UploadedBy='$username' OR (1=1 AND s.ProjectID IN ...)
// -> returns records for user's projects
// 4. WHERE mu.UploadedBy='$username'
// OR (1=1 AND s.CenterID IN ... AND s.ProjectID IN ...)
// -> returns records for user's sites and projects
// 5. WHERE mu.UploadedBy='$username'
// OR (1=1 AND s.CenterID IN ... AND s.ProjectID IN ...)
// OR mu.SessionID IS NULL
// -> returns records for user's sites and projects and null session data
// Other combinations are possible but order of operations still applies
$accessQuery = "SELECT *
FROM mri_upload mu
LEFT JOIN session s ON (s.ID = mu.SessionID)
";
$accessWhere = " WHERE (mu.UploadedBy='$username' OR 1=1 ";
if (!$user->hasPermission('imaging_uploader_allsites')) {
// Create where clause for sites
$accessWhere = $accessWhere . " AND s.CenterID IN ('$centerString') ";
}

if ($advancedperms === 'true') {
// If config setting is enabled, check the user's sites and projects
// site/project match + user's own uploads
$accessWhere = $accessWhere . " AND s.ProjectID IN ('$projectString')";
}

if ($user->hasPermission('imaging_uploader_nosessionid')) {
// clause for accessing null session data
$accessWhere = $accessWhere . " OR mu.SessionID IS NULL ";
}

// Wrap entire access logic in parentheses and add AND clause for specific upload ID
$accessWhere = $accessWhere . ") AND UploadId =:uploadId";

$accessData = $DB->pselectRow(
$accessQuery.$accessWhere,
['uploadId' => $uploadId]
);


if (empty($accessData)) {
http_response_code(403);
return;
}


/* Fetch columns Inserting and InsertionComplete from table mri_upload
* create Database object
*/
$DB = \NDB_Factory::singleton()->database();
$query = "SELECT Inserting, InsertionComplete
FROM mri_upload
WHERE UploadId =:uploadId";
Expand Down
Loading