silverstripe-framework/src/Control/Middleware/PermissionAwareConfirmation...

160 lines
4.3 KiB
PHP

<?php
namespace SilverStripe\Control\Middleware;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Security\Permission;
use SilverStripe\Security\Security;
/**
* Extends the ConfirmationMiddleware with checks for user permissions
*
* Respects users who don't have enough access and does not
* ask them for confirmation
*
* By default it enforces authentication by redirecting users to a login page.
*
* How it works:
* - if user can bypass the middleware, then pass request further
* - if there are no confirmation items, then pass request further
* - if user is not authenticated and enforceAuthentication is false, then pass request further
* - if user does not have at least one of the affected permissions, then pass request further
* - otherwise, pass handling to the parent (ConfirmationMiddleware)
*/
class PermissionAwareConfirmationMiddleware extends ConfirmationMiddleware
{
/**
* List of permissions affected by the middleware
*
* @see setAffectedPermissions method for more details
*
* @var string[]
*/
private $affectedPermissions = [];
/**
* Wthether the middleware should redirect to a login form
* if the user is not authenticated
*
* @var bool
*/
private $enforceAuthentication = true;
/**
* Returns the list of permissions that are affected
*
* @return string[]
*/
public function getAffectedPermissions()
{
return $this->affectedPermissions;
}
/**
* Set the list of affected permissions
*
* If the user doesn't have at least one of these, we assume they
* don't have access to the protected action, so we don't ask
* for a confirmation
*
* @param string[] $permissions list of affected permissions
*
* @return $this
*/
public function setAffectedPermissions($permissions)
{
$this->affectedPermissions = $permissions;
return $this;
}
/**
* Returns flag whether we want to enforce authentication or not
*
* @return bool
*/
public function getEnforceAuthentication()
{
return $this->enforceAuthentication;
}
/**
* Set whether we want to enforce authentication
*
* We either enforce authentication (redirect to a login form)
* or silently assume the user does not have permissions and
* so we don't have to ask for a confirmation
*
* @param bool $enforce
*
* @return $this
*/
public function setEnforceAuthentication($enforce)
{
$this->enforceAuthentication = $enforce;
return $this;
}
/**
* Check whether the user has permissions to perform the target operation
* Otherwise we may want to skip the confirmation dialog.
*
* WARNING! The user has to be authenticated beforehand
*
* @param HTTPRequest $request
*
* @return bool
*/
public function hasAccess(HTTPRequest $request)
{
foreach ($this->getAffectedPermissions() as $permission) {
if (Permission::check($permission)) {
return true;
}
}
return false;
}
/**
* Returns HTTPResponse with a redirect to a login page
*
* @param HTTPRequest $request
*
* @return HTTPResponse redirect to a login page
*/
protected function getAuthenticationRedirect(HTTPRequest $request)
{
$backURL = $request->getURL(true);
$loginPage = sprintf(
'%s?BackURL=%s',
Director::absoluteURL(Security::config()->get('login_url')),
urlencode($backURL)
);
$result = new HTTPResponse();
$result->redirect($loginPage);
return $result;
}
protected function processItems(HTTPRequest $request, callable $delegate, $items)
{
if (!Security::getCurrentUser()) {
if ($this->getEnforceAuthentication()) {
return $this->getAuthenticationRedirect($request);
} else {
// assume the user does not have permissions anyway
return $delegate($request);
}
}
if (!$this->hasAccess($request)) {
return $delegate($request);
}
return parent::processItems($request, $delegate, $items);
}
}