/
PermissionAwareConfirmationMiddleware.php
159 lines (143 loc) · 4.35 KB
/
PermissionAwareConfirmationMiddleware.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<?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);
}
}