Completed
Push — develop ( fa3ada...21e60e )
by
unknown
07:19
created

UserSwitcher   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 229
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 24
lcom 1
cbo 9
dl 0
loc 229
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A __invoke() 0 8 2
A setAclPlugin() 0 6 1
A getAclPlugin() 0 4 1
A clear() 0 15 2
A switchUser() 0 17 3
A isSwitchedUser() 0 6 2
A setSessionParams() 0 12 3
A getSessionParams() 0 6 2
A getSessionParam() 0 6 2
A setSessionParam() 0 4 1
A getSessionContainer() 0 8 2
A exchangeAuthUser() 0 13 2
1
<?php
2
/**
3
 * YAWIK
4
 *
5
 * @filesource
6
 * @license MIT
7
 * @copyright  2013 - 2017 Cross Solution <http://cross-solution.de>
8
 */
9
  
10
/** */
11
namespace Auth\Controller\Plugin;
12
13
use Acl\Controller\Plugin\Acl;
14
use Auth\Entity\UserInterface;
15
use Zend\Authentication\AuthenticationService;
16
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
17
use Zend\Session\Container;
18
use Zend\Stdlib\ArrayUtils;
19
20
/**
21
 * Plugin to switch logged in user w/o authentication.
22
 * 
23
 * @author Mathias Gelhausen <[email protected]>
24
 * @since 0.29
25
 */
26
class UserSwitcher extends AbstractPlugin
27
{
28
    const SESSION_NAMESPACE = "SwitchedUser";
29
30
    /**
31
     * AuthenticationService
32
     *
33
     * @var \Auth\AuthenticationService
34
     */
35
    private $auth;
36
37
    /**
38
     * The session container.
39
     *
40
     * @var Container
41
     */
42
    private $sessionContainer;
43
44
    /**
45
     *
46
     *
47
     * @var Acl
48
     */
49
    private $aclPlugin;
50
51
    /**
52
     * Creates an instance
53
     *
54
     * @param AuthenticationService $auth
55
     */
56
    public function __construct(AuthenticationService $auth)
57
    {
58
        $this->auth = $auth;
0 ignored issues
show
Documentation Bug introduced by
$auth is of type object<Zend\Authentication\AuthenticationService>, but the property $auth was declared to be of type object<Auth\AuthenticationService>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
59
    }
60
61
    /**
62
     * Switch to or restore an user.
63
     *
64
     * If $userId is not null, attempt to switch the user,
65
     * restore the original user otherwise.
66
     *
67
     * @param null|string $userId
68
     *
69
     * @return bool
70
     */
71
    public function __invoke($userId = null, array $params = [])
0 ignored issues
show
Coding Style introduced by
function __invoke() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
72
    {
73
        if (null === $userId) {
74
            return $this->clear();
75
        }
76
77
        return $this->switchUser($userId, $params);
78
    }
79
80
    /**
81
     * @param \Acl\Controller\Plugin\Acl $aclPlugin
82
     *
83
     * @return self
84
     */
85
    public function setAclPlugin($aclPlugin)
86
    {
87
        $this->aclPlugin = $aclPlugin;
88
89
        return $this;
90
    }
91
92
    /**
93
     * @return \Acl\Controller\Plugin\Acl
94
     */
95
    public function getAclPlugin()
96
    {
97
        return $this->aclPlugin;
98
    }
99
100
    /**
101
     * Restores the original user.
102
     *
103
     * @return bool
104
     */
105
    public function clear()
0 ignored issues
show
Coding Style introduced by
function clear() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
106
    {
107
        $session = $this->getSessionContainer();
108
        if (!$session->isSwitchedUser) {
109
            return false;
110
        }
111
112
        $originalUser = $session->originalUser;
113
        $this->exchangeAuthUser($originalUser);
114
        /* @var \Zend\Session\Storage\StorageInterface $sessionStorage */
115
        $sessionStorage = $session->getManager()->getStorage();
116
        $sessionStorage->clear(self::SESSION_NAMESPACE);
117
118
        return true;
119
    }
120
121
    /**
122
     * Switch to another user.
123
     *
124
     * @param string|UserInterface $id user id of the user to switch to.
125
     * @param array $params Additional parameters to store in the session container.
126
     *
127
     * @return bool
128
     */
129
    public function switchUser($id, array $params = [])
0 ignored issues
show
Coding Style introduced by
function switchUser() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
130
    {
131
        if ($id instanceOf UserInterface) {
132
            $id = $id->getId();
133
        }
134
135
        $session = $this->getSessionContainer();
136
        if ($session->isSwitchedUser) {
137
            return false;
138
        }
139
140
        $session->isSwitchedUser = true;
141
        $session->originalUser = $this->exchangeAuthUser($id);
142
        $session->params       = $params;
143
144
        return true;
145
    }
146
147
    /**
148
     * Is the current user a switched one?
149
     *
150
     * @return bool
151
     */
152
    public function isSwitchedUser()
153
    {
154
        $session = $this->getSessionContainer();
155
156
        return isset($session->isSwitchedUser) && $session->isSwitchedUser;
157
    }
158
159
    /**
160
     * Set additional params.
161
     *
162
     * @param array $params
163
     * @param bool  $merge Merges with existing params.
164
     *
165
     * @return self
166
     */
167
    public function setSessionParams(array $params, $merge = false)
168
    {
169
        $session = $this->getSessionContainer();
170
171
        if (isset($session->params) && $merge) {
172
            $params = ArrayUtils::merge($session->params, $params);
173
        }
174
175
        $session->params = $params;
176
177
        return $this;
178
    }
179
180
    /**
181
     * Get additional params
182
     *
183
     * @return array
184
     */
185
    public function getSessionParams()
186
    {
187
        $session = $this->getSessionContainer();
188
189
        return isset($session->params) ? $session->params : [];
190
    }
191
192
    /**
193
     * Get a param.
194
     *
195
     * @param string $key
196
     * @param mixed $default Value to return if param $key is not set.
197
     *
198
     * @return null
199
     */
200
    public function getSessionParam($key, $default = null)
201
    {
202
        $params = $this->getSessionParams();
203
204
        return array_key_exists($key, $params) ? $params[$key] : $default;
205
    }
206
207
    /**
208
     * Set a param.
209
     *
210
     * @param string $key
211
     * @param mixed $value
212
     *
213
     * @return UserSwitcher
214
     */
215
    public function setSessionParam($key, $value)
216
    {
217
        return $this->setSessionParams([$key => $value], true);
218
    }
219
220
    /**
221
     * Gets the session container.
222
     *
223
     * @return Container
224
     */
225
    private function getSessionContainer()
226
    {
227
        if (!$this->sessionContainer) {
228
            $this->sessionContainer = new Container(self::SESSION_NAMESPACE);
229
        }
230
231
        return $this->sessionContainer;
232
    }
233
234
    /**
235
     * Exchanges the authenticated user in AuthenticationService.
236
     *
237
     * @param string $id
238
     *
239
     * @return string The id of the previously authenticated user.
240
     */
241
    private function exchangeAuthUser($id)
242
    {
243
        $storage = $this->auth->getStorage();
244
        $originalUserId = $storage->read();
245
        $this->auth->clearIdentity();
246
        $storage->write($id);
247
248
        if ($acl = $this->getAclPlugin()) {
249
            $acl->setUser($this->auth->getUser());
250
        }
251
252
        return $originalUserId;
253
    }
254
}