160 lines
4.3 KiB
PHP
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);
|
|
}
|
|
}
|