Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Consolidate DO auth logic, refs #13437
- Move information object specific ACL logic to the
  QubitInformationObjectAcl subclass
- Consolidate information object digital object authorization logic
- Consolidate actor digital object authorization logic
- Update all digital object authorization checks to use the
  consolidated QubitAcl::check() method
- Merge duplicate code for getting a digital object URL to
  QubitObject::getDigitalObjectUrl() method
  • Loading branch information
djjuhasz committed Nov 13, 2020
1 parent e96e3b1 commit 6ccbded
Show file tree
Hide file tree
Showing 19 changed files with 410 additions and 241 deletions.
2 changes: 1 addition & 1 deletion apps/qubit/modules/actor/actions/indexAction.class.php
Expand Up @@ -43,6 +43,6 @@ public function execute($request)

$this->functions = QubitFunctionObject::get($criteria);

$this->digitalObjectLink = $this->resource->getDigitalObjectLink();
$this->digitalObjectLink = $this->resource->getDigitalObjectUrl();
}
}
Expand Up @@ -74,8 +74,7 @@ public function execute($request)
else
{
// Ensure the user has permissions to see a thumbnail
if (!QubitAcl::check($item->object, 'readThumbnail') ||
!QubitGrantedRight::checkPremis($item->object->id, 'readThumb'))
if (!QubitAcl::check($item->object, 'readThumbnail'))
{
$thumbnail = QubitDigitalObject::getGenericRepresentation(
$item->mimeType, QubitTerm::THUMBNAIL_ID
Expand Down
Expand Up @@ -51,48 +51,47 @@ public function execute($request)
// The preservation copy cannot be downloaded from AtoM
$this->canAccessPreservationCopy = false;

// AtoM's representations cannot be downloaded by default
// AtoM's representations cannot be accessed by default
$this->canAccessMasterFile = false;
$this->canAccessReferenceCopy = false;
$this->canAccessThumbnailCopy = false;

// Reasons for denying access to a AtoM's representations based on PREMIS rights
// Reasons for denying access to a DO representation based on PREMIS rights
$this->masterFileDenyReason = false;
$this->referenceCopyDenyReason = false;
$this->thumbnailCopyDenyReason = false;

// Group permissions always control access to AtoM's representations if the digital object is related to an actor
if ($this->relatedToActor && QubitAcl::check($this->resource->object, 'read'))
// If the digital object is related to an information object, and the user
// is not authenticated, access may be restricted by PREMIS rights, as well
// as standard ACL rules
if ($this->relatedToIo && !$this->user->isAuthenticated())
{
$this->canAccessMasterFile = true;
$this->canAccessReferenceCopy = true;
$this->canAccessThumbnailCopy = true;
}
$this->canAccessMasterFile = QubitGrantedRight::checkPremis(
$this->resource->object->id, 'readMaster', $this->masterFileDenyReason
) && QubitAcl::check($this->resource->object, 'readMaster');

// If the digital object is related to an information object, access to AtoM's representations is controlled by
// PREMIS rights (for authenticated users) or group permissions
if ($this->relatedToIo)
$this->canAccessReferenceCopy = QubitGrantedRight::checkPremis(
$this->resource->object->id, 'readReference', $this->referenceCopyDenyReason
) && QubitAcl::check($this->resource->object, 'readReference');

$this->canAccessThumbnailCopy = QubitGrantedRight::checkPremis(
$this->resource->object->id, 'readThumbnail', $this->thumbnailCopyDenyReason
) && QubitAcl::check($this->resource->object, 'readThumbnail');
}
else
{
if (
!$this->user->isAuthenticated()
&& QubitGrantedRight::hasGrantedRights($this->resource->object->id)
) {
$this->canAccessMasterFile = QubitGrantedRight::checkPremis(
$this->resource->object->id, 'readMaster', $this->masterFileDenyReason
);
$this->canAccessReferenceCopy = QubitGrantedRight::checkPremis(
$this->resource->object->id, 'readReference', $this->referenceCopyDenyReason
);
$this->canAccessThumbnailCopy = QubitGrantedRight::checkPremis(
$this->resource->object->id, 'readThumbnail', $this->thumbnailCopyDenyReason
);
}
else
{
$this->canAccessMasterFile = QubitAcl::check($this->resource->object, 'readMaster');
$this->canAccessReferenceCopy = QubitAcl::check($this->resource->object, 'readReference');
$this->canAccessThumbnailCopy = QubitAcl::check($this->resource->object, 'readThumbnail');
}
// Check ACL authorization
$this->canAccessMasterFile = QubitAcl::check(
$this->resource->object, 'readMaster'
);

$this->canAccessReferenceCopy = QubitAcl::check(
$this->resource->object, 'readReference'
);

$this->canAccessThumbnailCopy = QubitAcl::check(
$this->resource->object, 'readThumbnail'
);
}

// Statement shown as the Permissions field for preservation copies
Expand Down
46 changes: 16 additions & 30 deletions apps/qubit/modules/digitalobject/actions/showComponent.class.php
Expand Up @@ -41,11 +41,11 @@ public function execute($request)
$this->usageType = QubitTerm::THUMBNAIL_ID;
}

if ((QubitTerm::MASTER_ID == $this->usageType &&
!QubitAcl::check($this->resource->object, 'readMaster') &&
$this->resource->object instanceOf QubitInformationObject) ||
$this->resource->object instanceOf QubitActor &&
!QubitAcl::check($this->resource->object, 'read'))
// Don't show anything if trying to view a master DO without authorization
if (
QubitTerm::MASTER_ID == $this->usageType
&& !QubitAcl::check($this->resource->object, 'readMaster')
)
{
return sfView::NONE;
}
Expand All @@ -59,6 +59,8 @@ public function execute($request)
$this->showComponent = 'showGenericIcon';
}

// Check PREMIS granted rights, and show an access warning if they prevent
// access
if ($this->usageType == QubitTerm::REFERENCE_ID)
{
$this->accessWarning = $this->getAccessWarning();
Expand All @@ -80,24 +82,9 @@ public function execute($request)
*/
private function checkShowGenericIcon()
{
$curUser = sfContext::getInstance()->getUser();
$curObjectId = $this->resource->object->id;

if ($this->resource->object instanceOf QubitActor)
{
return !QubitAcl::check($this->resource->object, 'read');
}

switch ($this->usageType)
{
case QubitTerm::REFERENCE_ID:
// Non-authenticated user: check against PREMIS rules.
if (!$curUser->isAuthenticated() && QubitGrantedRight::hasGrantedRights($curObjectId))
{
return !QubitGrantedRight::checkPremis($curObjectId, 'readReference');
}

// Authenticated, check regular ACL rules...
return !QubitAcl::check($this->resource->object, 'readReference');

case QubitTerm::THUMBNAIL_ID:
Expand All @@ -106,26 +93,25 @@ private function checkShowGenericIcon()
}

/**
* Get warning messages if access denied via 'deny' or 'conditional' PREMIS rules.
* @return A string of the warning if reference access denied, otherwise bool false
* Get warning messages if access denied via 'deny' or 'conditional' PREMIS
* rules
*
* @return string Custom PREMIS "access denied" message, or an empty string
*/
private function getAccessWarning()
{
$curObjectId = $this->resource->object->id;
$denyReason = '';

if ($this->resource->object instanceOf QubitActor)
{
return false;
return '';
}

if (!QubitGrantedRight::checkPremis($curObjectId, 'readReference', $denyReason) ||
!QubitAcl::check($this->resource->object, 'readReference'))
{
return $denyReason;
}
QubitGrantedRight::checkPremis(
$this->resource->object->id, 'readReference', $denyReason
);

return false;
return $denyReason;
}

private function setComponentType()
Expand Down
Expand Up @@ -58,9 +58,13 @@ public function execute($request)
}

// Build a fully qualified URL to this digital object asset
if ((QubitTerm::IMAGE_ID != $this->resource->mediaTypeId || QubitTerm::REFERENCE_ID == $this->usageType)
&& $this->resource->usageId != QubitTerm::OFFLINE_ID
&& QubitAcl::check($this->resource->object, 'readMaster'))
if (
(
QubitTerm::IMAGE_ID != $this->resource->mediaTypeId
|| QubitTerm::REFERENCE_ID == $this->usageType
)
&& $this->resource->usageId != QubitTerm::OFFLINE_ID
&& QubitAcl::check($this->resource->object, 'readMaster'))
{
$this->link = $this->resource->getPublicPath();
}
Expand Down
Expand Up @@ -18,7 +18,7 @@
*/

/**
* Display an 'image' digital asset
* Display a generic representation of a digital object
*
* @package AccesstoMemory
* @subpackage digital object
Expand All @@ -27,23 +27,18 @@
class DigitalObjectShowGenericIconComponent extends sfComponent
{
/**
* Show a representation of a digital object image.
* Show a generic representation of a digital object image
*
* @param sfWebRequest $request
*
*/
public function execute($request)
{
$this->representation = QubitDigitalObject::getGenericRepresentation($this->resource->mimeType, $this->resource->usageId);
$this->representation = QubitDigitalObject::getGenericRepresentation(
$this->resource->mimeType, $this->resource->usageId
);

if ($this->resource->object instanceOf QubitInformationObject)
{
$this->canReadMaster = QubitAcl::check($this->resource->object, 'readMaster');
}
else if ($this->resource->object instanceOf QubitActor &&
$this->context->user->isAuthenticated())
{
$this->canReadMaster = QubitAcl::check($this->resource->object, 'read');;
}
$this->canReadMaster = QubitAcl::check(
$this->resource->object, 'readMaster'
);
}
}
7 changes: 2 additions & 5 deletions apps/qubit/modules/digitalobject/actions/viewAction.class.php
Expand Up @@ -44,11 +44,8 @@ public function execute($request)

list($obj, $action) = $this->getObjAndAction();

// Do appropriate ACL check(s). Master copy of text objects are always allowed for reading
// QubitActor does not have a ACL check for readmaster.
if ((!QubitAcl::check($obj, $action) || !QubitGrantedRight::checkPremis($obj->id, $action))
&& !($action == 'readMaster' && $this->resource->mediaTypeId == QubitTerm::TEXT_ID)
&& $obj instanceOf QubitInformationObject)
// If access is denied, forward user to a 404 "Not found" page
if (!QubitAcl::check($obj, $action))
{
$this->forward404();
}
Expand Down
2 changes: 1 addition & 1 deletion apps/qubit/modules/digitalobject/templates/_metadata.php
Expand Up @@ -133,7 +133,7 @@

<?php if ($showMasterFileName): ?>
<?php if ($canAccessMasterFile): ?>
<?php echo render_show(__('Filename'), link_to(render_value_inline($resource->name), $resource->object->getDigitalObjectLink(), array('target' => '_blank')), array('fieldLabel' => 'filename')) ?>
<?php echo render_show(__('Filename'), link_to(render_value_inline($resource->name), $resource->object->getDigitalObjectUrl(), array('target' => '_blank')), array('fieldLabel' => 'filename')) ?>
<?php else: ?>
<?php echo render_show(__('Filename'), render_value($resource->name), array('fieldLabel' => 'filename')) ?>
<?php endif; ?>
Expand Down
Expand Up @@ -130,6 +130,6 @@ public function execute($request)
$this->response->addMeta('description', truncate_text(strip_markdown($scopeAndContent), 150));
}

$this->digitalObjectLink = $this->resource->getDigitalObjectLink();
$this->digitalObjectLink = $this->resource->getDigitalObjectUrl();
}
}
Expand Up @@ -13,9 +13,11 @@
<?php endif; ?>

<a href="<?php echo url_for(array('module' => 'informationobject', 'slug' => $doc['slug'])) ?>">
<?php if (isset($doc['digitalObject']) && !empty($doc['digitalObject']['thumbnailPath'])
<?php if (
isset($doc['digitalObject'])
&& !empty($doc['digitalObject']['thumbnailPath'])
&& QubitAcl::check(QubitInformationObject::getById($hit->getId()), 'readThumbnail')
&& QubitGrantedRight::checkPremis($hit->getId(), 'readThumb')): ?>
): ?>

<?php echo link_to(image_tag($doc['digitalObject']['thumbnailPath'],
array('alt' => isset($doc['digitalObject']['digitalObjectAltText']) ? $doc['digitalObject']['digitalObjectAltText'] : truncate_text(strip_markdown($title), 100))),
Expand Down
Expand Up @@ -55,7 +55,7 @@
<td>
<?php if ($doc['hasDigitalObject']): ?>
<?php if (null !== $io = QubitInformationObject::getById($hit->getId())): ?>
<?php if (null !== $link = $io->getDigitalObjectLink()): ?>
<?php if (null !== $link = $io->getDigitalObjectUrl()): ?>
<?php echo link_to(__('View'), $link) ?>
<?php endif; ?>
<?php endif; ?>
Expand Down
8 changes: 5 additions & 3 deletions apps/qubit/modules/search/templates/_searchResult.php
Expand Up @@ -11,9 +11,11 @@
<div class="search-result-preview">
<a href="<?php echo url_for(array('module' => 'informationobject', 'slug' => $doc['slug'])) ?>">
<div class="preview-container">
<?php if (isset($doc['digitalObject']['thumbnailPath']) &&
QubitAcl::check(QubitInformationObject::getById($hit->getId()), 'readThumbnail') &&
QubitGrantedRight::checkPremis($hit->getId(), 'readThumb')): ?>
<?php if (
isset($doc['digitalObject']['thumbnailPath']) &&
QubitAcl::check(QubitInformationObject::getById($hit->getId()), 'readThumbnail')
):
?>
<?php echo image_tag($doc['digitalObject']['thumbnailPath'],
array('alt' => isset($doc['digitalObject']['digitalObjectAltText']) ? $doc['digitalObject']['digitalObjectAltText'] : truncate_text(strip_markdown(get_search_i18n($doc, 'title', array('allowEmpty' => false, 'culture' => $culture))), 100))) ?>
<?php else: ?>
Expand Down
25 changes: 5 additions & 20 deletions lib/job/arExportJob.class.php
Expand Up @@ -314,28 +314,13 @@ protected function addDigitalObject($resource, $tempDir)

protected function allowDigitalObjectExport($resource, $digitalObject)
{
// If we need to add in check for images only, then use:
// $digitalObject->isImage() or
// $digitalObject->isWebCompatibleImageFormat()
// ----------
// Do appropriate ACL check(s). Master copy of text objects are always
// allowed for reading. QubitActor does not have a ACL check for
// readMaster - so only enable for authenticated users.
// Check that digital object has a URL, the current user is authorized to
// access it, and a conditional copyright statement doesn't need to be
// accepted
if (
$digitalObject->masterAccessibleViaUrl()
&& (
QubitTerm::TEXT_ID == $digitalObject->mediaTypeId
|| (
'actor' == $this->params['objectType']
&& $this->user->isAuthenticated()
&& QubitAcl::check($resource, 'read')
) || (
'informationObject' == $this->params['objectType']
&& QubitAcl::check($resource, 'readMaster')
&& QubitGrantedRight::checkPremis($resource->id, 'readMaster')
&& !$digitalObject->hasConditionalCopyright()
)
)
&& QubitAcl::check($resource, 'readMaster')
&& !$digitalObject->hasConditionalCopyright()
)
{
// Export is allowed
Expand Down
37 changes: 0 additions & 37 deletions lib/model/QubitActor.php
Expand Up @@ -813,41 +813,4 @@ public function importDigitalObjectFromBase64($encodedString, $filename)

$this->digitalObjectsRelatedByobjectId[] = $digitalObject;
}

/**
* Return the absolute link to the digital object master unless the user has
* no permission (readMaster). Text objects are always allowed for reading.
*
* @return string Absolute link to the digital object master
*/
public function getDigitalObjectLink()
{
if (count($this->digitalObjectsRelatedByobjectId) <= 0)
{
return;
}

$digitalObject = $this->digitalObjectsRelatedByobjectId[0];
if (!$digitalObject->masterAccessibleViaUrl())
{
return;
}

$isText = in_array($digitalObject->mediaTypeId, array(QubitTerm::TEXT_ID));

$hasReadMaster = sfContext::getInstance()->user->isAuthenticated();
if ($hasReadMaster || $isText)
{
if (QubitTerm::EXTERNAL_URI_ID == $digitalObject->usageId)
{
return $digitalObject->path;
}
else
{
$request = sfContext::getInstance()->getRequest();
return $request->getUriPrefix().$request->getRelativeUrlRoot().
$digitalObject->getFullPath();
}
}
}
}

0 comments on commit 6ccbded

Please sign in to comment.