Files
OSJ/lib/pkp/classes/security/authorization/SubmissionFileAccessPolicy.php
CHIEFSOFT\ameye df3a033196 first commit
2024-06-08 17:09:23 -04:00

275 lines
15 KiB
PHP

<?php
/**
* @file classes/security/authorization/SubmissionFileAccessPolicy.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class SubmissionFileAccessPolicy
*
* @ingroup security_authorization
*
* @brief Base class to control (write) access to submissions and (read) access to
* submission files.
*/
namespace PKP\security\authorization;
use PKP\core\PKPRequest;
use PKP\security\authorization\internal\ContextPolicy;
use PKP\security\authorization\internal\SubmissionFileAssignedQueryAccessPolicy;
use PKP\security\authorization\internal\SubmissionFileAssignedReviewerAccessPolicy;
use PKP\security\authorization\internal\SubmissionFileAuthorEditorPolicy;
use PKP\security\authorization\internal\SubmissionFileMatchesSubmissionPolicy;
use PKP\security\authorization\internal\SubmissionFileMatchesWorkflowStageIdPolicy;
use PKP\security\authorization\internal\SubmissionFileNotQueryAccessPolicy;
use PKP\security\authorization\internal\SubmissionFileRequestedRevisionRequiredPolicy;
use PKP\security\authorization\internal\SubmissionFileStageRequiredPolicy;
use PKP\security\authorization\internal\SubmissionFileUploaderAccessPolicy;
use PKP\security\authorization\internal\SubmissionRequiredPolicy;
use PKP\security\authorization\internal\UserAccessibleWorkflowStageRequiredPolicy;
use PKP\security\authorization\internal\WorkflowStageRequiredPolicy;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class SubmissionFileAccessPolicy extends ContextPolicy
{
// Define the bitfield for submission file access levels
public const SUBMISSION_FILE_ACCESS_READ = 1;
public const SUBMISSION_FILE_ACCESS_MODIFY = 2;
/** @var PolicySet $_baseFileAccessPolicy the base file file policy before _SUB_EDITOR is considered */
public $_baseFileAccessPolicy;
/**
* Constructor
*
* @param PKPRequest $request
* @param array $args request parameters
* @param array $roleAssignments
* @param int $mode bitfield SubmissionFileAccessPolicy::SUBMISSION_FILE_ACCESS_...
* @param int $submissionFileId
* @param string $submissionParameterName the request parameter we expect
* the submission id in.
*/
public function __construct($request, $args, $roleAssignments, $mode, $submissionFileId = null, $submissionParameterName = 'submissionId')
{
// TODO: Refine file access policies. Differentiate between
// read and modify access using bitfield:
// $mode & SubmissionFileAccessPolicy::SUBMISSION_FILE_ACCESS_...
parent::__construct($request);
$this->_baseFileAccessPolicy = $this->buildFileAccessPolicy($request, $args, $roleAssignments, $mode, $submissionFileId, $submissionParameterName);
}
/**
*
* @param PKPRequest $request
* @param array $args
* @param array $roleAssignments
* @param int $mode bitfield
* @param int $submissionFileId
* @param string $submissionParameterName
*/
public function buildFileAccessPolicy($request, $args, $roleAssignments, $mode, $submissionFileId, $submissionParameterName)
{
// We need a submission matching the file in the request.
$this->addPolicy(new SubmissionRequiredPolicy($request, $args, $submissionParameterName));
$this->addPolicy(new SubmissionFileMatchesSubmissionPolicy($request, $submissionFileId));
// Authors, managers and series editors potentially have
// access to submission files. We'll have to define
// differentiated policies for those roles in a policy set.
$fileAccessPolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
//
// Site administrator role
if (isset($roleAssignments[Role::ROLE_ID_SITE_ADMIN])) {
$adminPolicy = new PolicySet(PolicySet::COMBINING_DENY_OVERRIDES);
$adminPolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, Role::ROLE_ID_SITE_ADMIN, $roleAssignments[Role::ROLE_ID_SITE_ADMIN]));
// A valid workflow stage needs to be in the authorized objects for most file operations
$stageId = (int) $request->getUserVar('stageId');
$adminPolicy->addPolicy(new WorkflowStageRequiredPolicy($stageId));
$fileAccessPolicy->addPolicy($adminPolicy);
}
//
// Managerial role
//
if (isset($roleAssignments[Role::ROLE_ID_MANAGER])) {
// Managers can access all submission files as long as the manager has not
// been assigned to a lesser role in the stage.
$managerFileAccessPolicy = new PolicySet(PolicySet::COMBINING_DENY_OVERRIDES);
$managerFileAccessPolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, Role::ROLE_ID_MANAGER, $roleAssignments[Role::ROLE_ID_MANAGER]));
$stageId = $request->getUserVar('stageId'); // WORKFLOW_STAGE_ID_...
$managerFileAccessPolicy->addPolicy(new SubmissionFileMatchesWorkflowStageIdPolicy($request, $submissionFileId, $stageId));
$managerFileAccessPolicy->addPolicy(new WorkflowStageAccessPolicy($request, $args, $roleAssignments, 'submissionId', $stageId));
$managerFileAccessPolicy->addPolicy(new AssignedStageRoleHandlerOperationPolicy($request, Role::ROLE_ID_MANAGER, $roleAssignments[Role::ROLE_ID_MANAGER], $stageId));
$fileAccessPolicy->addPolicy($managerFileAccessPolicy);
}
//
// Author role
//
if (isset($roleAssignments[Role::ROLE_ID_AUTHOR])) {
// 1) Author role user groups can access whitelisted operations ...
$authorFileAccessPolicy = new PolicySet(PolicySet::COMBINING_DENY_OVERRIDES);
$authorFileAccessPolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, Role::ROLE_ID_AUTHOR, $roleAssignments[Role::ROLE_ID_AUTHOR]));
// 2) ...if they are assigned to the workflow stage as an author. Note: This loads the application-specific policy class.
$stageId = $request->getUserVar('stageId');
$authorFileAccessPolicy->addPolicy(new WorkflowStageAccessPolicy($request, $args, $roleAssignments, 'submissionId', $stageId));
$authorFileAccessPolicy->addPolicy(new SubmissionFileMatchesWorkflowStageIdPolicy($request, $submissionFileId, $stageId));
$authorFileAccessPolicy->addPolicy(new AssignedStageRoleHandlerOperationPolicy($request, Role::ROLE_ID_AUTHOR, $roleAssignments[Role::ROLE_ID_AUTHOR], $stageId));
// 3) ...and if they meet one of the following requirements:
$authorFileAccessOptionsPolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
// 3a) If the file was uploaded by the current user, allow...
$authorFileAccessOptionsPolicy->addPolicy(new SubmissionFileUploaderAccessPolicy($request, $submissionFileId));
// 3b) ...or if the file is a file in a review round with requested revision decision, allow...
// Note: This loads the application-specific policy class
$authorFileAccessOptionsPolicy->addPolicy(new SubmissionFileRequestedRevisionRequiredPolicy($request, $submissionFileId));
// ...or if we don't want to modify the file...
if (!($mode & self::SUBMISSION_FILE_ACCESS_MODIFY)) {
// 3c) ...the file is at submission stage...
$authorFileAccessOptionsPolicy->addPolicy(new SubmissionFileStageRequiredPolicy($request, $submissionFileId, SubmissionFile::SUBMISSION_FILE_SUBMISSION));
// 3d) ...or the file is a viewable reviewer response...
$authorFileAccessOptionsPolicy->addPolicy(new SubmissionFileStageRequiredPolicy($request, $submissionFileId, SubmissionFile::SUBMISSION_FILE_REVIEW_ATTACHMENT, true));
// 3e) ...or if the file is part of a query assigned to the user...
$authorFileAccessOptionsPolicy->addPolicy(new SubmissionFileAssignedQueryAccessPolicy($request, $submissionFileId));
// 3f) ...or the file is at revision stage...
$authorFileAccessOptionsPolicy->addPolicy(new SubmissionFileStageRequiredPolicy($request, $submissionFileId, SubmissionFile::SUBMISSION_FILE_REVIEW_REVISION));
// 3f) ...or the file is at revision stage...
$authorFileAccessOptionsPolicy->addPolicy(new SubmissionFileStageRequiredPolicy($request, $submissionFileId, SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_REVISION));
// 3g) ...or the file is a copyedited file...
$authorFileAccessOptionsPolicy->addPolicy(new SubmissionFileStageRequiredPolicy($request, $submissionFileId, SubmissionFile::SUBMISSION_FILE_COPYEDIT));
// 3h) ...or the file is a representation (galley/publication format)...
$authorFileAccessOptionsPolicy->addPolicy(new SubmissionFileStageRequiredPolicy($request, $submissionFileId, SubmissionFile::SUBMISSION_FILE_PROOF));
}
// Add the rules from 3)
$authorFileAccessPolicy->addPolicy($authorFileAccessOptionsPolicy);
$fileAccessPolicy->addPolicy($authorFileAccessPolicy);
}
//
// Reviewer role
//
if (isset($roleAssignments[Role::ROLE_ID_REVIEWER])) {
// 1) Reviewers can access whitelisted operations ...
$reviewerFileAccessPolicy = new PolicySet(PolicySet::COMBINING_DENY_OVERRIDES);
$reviewerFileAccessPolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, Role::ROLE_ID_REVIEWER, $roleAssignments[Role::ROLE_ID_REVIEWER]));
// 2) ...if they meet one of the following requirements:
$reviewerFileAccessOptionsPolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
// 2a) If the file was uploaded by the current user, allow.
$reviewerFileAccessOptionsPolicy->addPolicy(new SubmissionFileUploaderAccessPolicy($request, $submissionFileId));
// 2b) If the file is part of an assigned review, and we're not
// trying to modify it, allow.
if (!($mode & self::SUBMISSION_FILE_ACCESS_MODIFY)) {
$reviewerFileAccessOptionsPolicy->addPolicy(new SubmissionFileAssignedReviewerAccessPolicy($request, $submissionFileId));
}
// 2c) If the file is part of a query assigned to the user, allow.
$reviewerFileAccessOptionsPolicy->addPolicy(new SubmissionFileAssignedQueryAccessPolicy($request, $submissionFileId));
// Add the rules from 2)
$reviewerFileAccessPolicy->addPolicy($reviewerFileAccessOptionsPolicy);
// Add this policy set
$fileAccessPolicy->addPolicy($reviewerFileAccessPolicy);
}
//
// Assistant role.
//
if (isset($roleAssignments[Role::ROLE_ID_ASSISTANT])) {
// 1) Assistants can access whitelisted operations...
$contextAssistantFileAccessPolicy = new PolicySet(PolicySet::COMBINING_DENY_OVERRIDES);
$contextAssistantFileAccessPolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, Role::ROLE_ID_ASSISTANT, $roleAssignments[Role::ROLE_ID_ASSISTANT]));
// 2) ... but only if they have been assigned to the submission workflow as an assistant.
// Note: This loads the application-specific policy class
$stageId = $request->getUserVar('stageId');
$contextAssistantFileAccessPolicy->addPolicy(new WorkflowStageAccessPolicy($request, $args, $roleAssignments, 'submissionId', $stageId));
$contextAssistantFileAccessPolicy->addPolicy(new SubmissionFileMatchesWorkflowStageIdPolicy($request, $submissionFileId, $stageId));
$contextAssistantFileAccessPolicy->addPolicy(new AssignedStageRoleHandlerOperationPolicy($request, Role::ROLE_ID_ASSISTANT, $roleAssignments[Role::ROLE_ID_ASSISTANT], $stageId));
// 3) ...and if they meet one of the following requirements:
$contextAssistantFileAccessOptionsPolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
// 3a) ...the file not part of a query...
$contextAssistantFileAccessOptionsPolicy->addPolicy(new SubmissionFileNotQueryAccessPolicy($request, $submissionFileId));
// 3b) ...or the file is part of a query they are assigned to...
$contextAssistantFileAccessOptionsPolicy->addPolicy(new SubmissionFileAssignedQueryAccessPolicy($request, $submissionFileId));
// Add the rules from 3
$contextAssistantFileAccessPolicy->addPolicy($contextAssistantFileAccessOptionsPolicy);
$fileAccessPolicy->addPolicy($contextAssistantFileAccessPolicy);
}
//
// Sub editor role
//
if (isset($roleAssignments[Role::ROLE_ID_SUB_EDITOR])) {
// 1) Sub editors can access all operations on submissions ...
$subEditorFileAccessPolicy = new PolicySet(PolicySet::COMBINING_DENY_OVERRIDES);
$subEditorFileAccessPolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, Role::ROLE_ID_SUB_EDITOR, $roleAssignments[Role::ROLE_ID_SUB_EDITOR]));
// 2) ... but only if they have been assigned as a subeditor to the requested submission ...
$stageId = $request->getUserVar('stageId');
$subEditorFileAccessPolicy->addPolicy(new WorkflowStageAccessPolicy($request, $args, $roleAssignments, 'submissionId', $stageId));
$subEditorFileAccessPolicy->addPolicy(new UserAccessibleWorkflowStageRequiredPolicy($request));
$subEditorFileAccessPolicy->addPolicy(new AssignedStageRoleHandlerOperationPolicy($request, Role::ROLE_ID_SUB_EDITOR, $roleAssignments[Role::ROLE_ID_SUB_EDITOR], $stageId));
$subEditorFileAccessPolicy->addPolicy(new SubmissionFileMatchesWorkflowStageIdPolicy($request, $submissionFileId, $stageId));
// 3) ...and if they meet one of the following requirements:
$subEditorQueryFileAccessPolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
// 3a) ...the file not part of a query...
$subEditorQueryFileAccessPolicy->addPolicy(new SubmissionFileNotQueryAccessPolicy($request, $submissionFileId));
// 3b) ...or the file is part of a query they are assigned to...
$subEditorQueryFileAccessPolicy->addPolicy(new SubmissionFileAssignedQueryAccessPolicy($request, $submissionFileId));
// Add the rules from 3
$subEditorFileAccessPolicy->addPolicy($subEditorQueryFileAccessPolicy);
// 4) ... and only if they are not also assigned as an author and this is not part of a anonymous review
$subEditorFileAccessPolicy->addPolicy(new SubmissionFileAuthorEditorPolicy($request, $submissionFileId));
$fileAccessPolicy->addPolicy($subEditorFileAccessPolicy);
}
$this->addPolicy($fileAccessPolicy);
return $fileAccessPolicy;
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\security\authorization\SubmissionFileAccessPolicy', '\SubmissionFileAccessPolicy');
define('SUBMISSION_FILE_ACCESS_READ', SubmissionFileAccessPolicy::SUBMISSION_FILE_ACCESS_READ);
define('SUBMISSION_FILE_ACCESS_MODIFY', SubmissionFileAccessPolicy::SUBMISSION_FILE_ACCESS_MODIFY);
}