Passed
Push — master ( ddbf8b...086098 )
by Robbie
11:17
created

PermissionAwareConfirmationMiddleware   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 132
rs 10
c 0
b 0
f 0
wmc 12

7 Methods

Rating   Name   Duplication   Size   Complexity  
A setEnforceAuthentication() 0 4 1
A hasAccess() 0 9 3
A getAuthenticationRedirect() 0 13 1
A getEnforceAuthentication() 0 3 1
A processItems() 0 16 4
A setAffectedPermissions() 0 4 1
A getAffectedPermissions() 0 3 1
1
<?php
2
3
namespace SilverStripe\Control\Middleware;
4
5
use SilverStripe\Control\Director;
6
use SilverStripe\Control\HTTPRequest;
7
use SilverStripe\Control\HTTPResponse;
8
use SilverStripe\Security\Permission;
9
use SilverStripe\Security\Security;
10
11
/**
12
 * Extends the ConfirmationMiddleware with checks for user permissions
13
 *
14
 * Respects users who don't have enough access and does not
15
 * ask them for confirmation
16
 *
17
 * By default it enforces authentication by redirecting users to a login page.
18
 *
19
 * How it works:
20
 *  - if user can bypass the middleware, then pass request further
21
 *  - if there are no confirmation items, then pass request further
22
 *  - if user is not authenticated and enforceAuthentication is false, then pass request further
23
 *  - if user does not have at least one of the affected permissions, then pass request further
24
 *  - otherwise, pass handling to the parent (ConfirmationMiddleware)
25
 */
26
class PermissionAwareConfirmationMiddleware extends ConfirmationMiddleware
27
{
28
    /**
29
     * List of permissions affected by the middleware
30
     *
31
     * @see setAffectedPermissions method for more details
32
     *
33
     * @var string[]
34
     */
35
    private $affectedPermissions = [];
36
37
    /**
38
     * Wthether the middleware should redirect to a login form
39
     * if the user is not authenticated
40
     *
41
     * @var bool
42
     */
43
    private $enforceAuthentication = true;
44
45
    /**
46
     * Returns the list of permissions that are affected
47
     *
48
     * @return string[]
49
     */
50
    public function getAffectedPermissions()
51
    {
52
        return $this->affectedPermissions;
53
    }
54
55
    /**
56
     * Set the list of affected permissions
57
     *
58
     * If the user doesn't have at least one of these, we assume they
59
     * don't have access to the protected action, so we don't ask
60
     * for a confirmation
61
     *
62
     * @param string[] $permissions list of affected permissions
63
     *
64
     * @return $this
65
     */
66
    public function setAffectedPermissions($permissions)
67
    {
68
        $this->affectedPermissions = $permissions;
69
        return $this;
70
    }
71
72
    /**
73
     * Returns flag whether we want to enforce authentication or not
74
     *
75
     * @return bool
76
     */
77
    public function getEnforceAuthentication()
78
    {
79
        return $this->enforceAuthentication;
80
    }
81
82
    /**
83
     * Set whether we want to enforce authentication
84
     *
85
     * We either enforce authentication (redirect to a login form)
86
     * or silently assume the user does not have permissions and
87
     * so we don't have to ask for a confirmation
88
     *
89
     * @param bool $enforce
90
     *
91
     * @return $this
92
     */
93
    public function setEnforceAuthentication($enforce)
94
    {
95
        $this->enforceAuthentication = $enforce;
96
        return $this;
97
    }
98
99
    /**
100
     * Check whether the user has permissions to perform the target operation
101
     * Otherwise we may want to skip the confirmation dialog.
102
     *
103
     * WARNING! The user has to be authenticated beforehand
104
     *
105
     * @param HTTPRequest $request
106
     *
107
     * @return bool
108
     */
109
    public function hasAccess(HTTPRequest $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

109
    public function hasAccess(/** @scrutinizer ignore-unused */ HTTPRequest $request)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
110
    {
111
        foreach ($this->getAffectedPermissions() as $permission) {
112
            if (Permission::check($permission)) {
113
                return true;
114
            }
115
        }
116
117
        return false;
118
    }
119
120
    /**
121
     * Returns HTTPResponse with a redirect to a login page
122
     *
123
     * @param HTTPRequest $request
124
     *
125
     * @return HTTPResponse redirect to a login page
126
     */
127
    protected function getAuthenticationRedirect(HTTPRequest $request)
128
    {
129
        $backURL = $request->getURL(true);
130
131
        $loginPage = sprintf(
132
            '%s?BackURL=%s',
133
            Director::absoluteURL(Security::config()->get('login_url')),
134
            urlencode($backURL)
135
        );
136
137
        $result = new HTTPResponse();
138
        $result->redirect($loginPage);
139
        return $result;
140
    }
141
142
    protected function processItems(HTTPRequest $request, callable $delegate, $items)
143
    {
144
        if (!Security::getCurrentUser()) {
145
            if ($this->getEnforceAuthentication()) {
146
                return $this->getAuthenticationRedirect($request);
147
            } else {
148
                // assume the user does not have permissions anyway
149
                return $delegate($request);
150
            }
151
        }
152
153
        if (!$this->hasAccess($request)) {
154
            return $delegate($request);
155
        }
156
157
        return parent::processItems($request, $delegate, $items);
158
    }
159
}
160