Issues (174)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

rbac/DbManager.php (8 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 *  _   __ __ _____ _____ ___  ____  _____
5
 * | | / // // ___//_  _//   ||  __||_   _|
6
 * | |/ // /(__  )  / / / /| || |     | |
7
 * |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link https://vistart.me/
9
 * @copyright Copyright (c) 2016 - 2017 vistart
10
 * @license https://vistart.me/license/
11
 */
12
13
namespace rhosocial\user\rbac;
14
15
use rhosocial\user\User;
16
use yii\db\Expression;
17
use yii\db\Query;
18
19
/**
20
 * This DbManager replaces the UserID of original DbManager with the UserGUID.
21
 *
22
 * @see User
23
 * @version 1.0
24
 * @author vistart <[email protected]>
25
 */
26
class DbManager extends \yii\rbac\DbManager
27
{
28
    /**
29
     * @inheritdoc
30
     */
31
    protected function addItem($item)
32
    {
33
        $time = gmdate('Y-m-d H:i:s');
34
        if ($item->createdAt === null) {
35
            $item->createdAt = $time;
0 ignored issues
show
Documentation Bug introduced by
The property $createdAt was declared of type integer, but $time is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
36
        }
37
        if ($item->updatedAt === null) {
38
            $item->updatedAt = $time;
0 ignored issues
show
Documentation Bug introduced by
The property $updatedAt was declared of type integer, but $time is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
39
        }
40
        $this->db->createCommand()
41
            ->insert($this->itemTable, [
42
                'name' => $item->name,
43
                'type' => $item->type,
44
                'description' => $item->description,
45
                'rule_name' => $item->ruleName,
46
                'data' => $item->data === null ? null : serialize($item->data),
47
                'created_at' => $item->createdAt,
48
                'updated_at' => $item->updatedAt,
49
            ])->execute();
50
51
        $this->invalidateCache();
52
53
        return true;
54
    }
55
    
56
    /**
57
     * @inheritdoc
58
     */
59
    protected function updateItem($name, $item)
60
    {
61
        if ($item->name !== $name && !$this->supportsCascadeUpdate()) {
62
            $this->db->createCommand()
63
                ->update($this->itemChildTable, ['parent' => $item->name], ['parent' => $name])
64
                ->execute();
65
            $this->db->createCommand()
66
                ->update($this->itemChildTable, ['child' => $item->name], ['child' => $name])
67
                ->execute();
68
            $this->db->createCommand()
69
                ->update($this->assignmentTable, ['item_name' => $item->name], ['item_name' => $name])
70
                ->execute();
71
        }
72
73
        $item->updatedAt = gmdate('Y-m-d H:i:s');
0 ignored issues
show
Documentation Bug introduced by
The property $updatedAt was declared of type integer, but gmdate('Y-m-d H:i:s') is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
74
75
        $this->db->createCommand()
76
            ->update($this->itemTable, [
77
                'name' => $item->name,
78
                'description' => $item->description,
79
                'rule_name' => $item->ruleName,
80
                'data' => $item->data === null ? null : serialize($item->data),
81
                'updated_at' => $item->updatedAt,
82
            ], [
83
                'name' => $name,
84
            ])->execute();
85
86
        $this->invalidateCache();
87
88
        return true;
89
    }
90
91
    /**
92
     * @inheritdoc
93
     */
94
    protected function addRule($rule)
95
    {
96
        $time = gmdate('Y-m-d H:i:s');
97
        if ($rule->createdAt === null) {
98
            $rule->createdAt = $time;
0 ignored issues
show
Documentation Bug introduced by
The property $createdAt was declared of type integer, but $time is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
99
        }
100
        if ($rule->updatedAt === null) {
101
            $rule->updatedAt = $time;
0 ignored issues
show
Documentation Bug introduced by
The property $updatedAt was declared of type integer, but $time is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
102
        }
103
        $this->db->createCommand()
104
            ->insert($this->ruleTable, [
105
                'name' => $rule->name,
106
                'data' => serialize($rule),
107
                'created_at' => $rule->createdAt,
108
                'updated_at' => $rule->updatedAt,
109
            ])->execute();
110
111
        $this->invalidateCache();
112
113
        return true;
114
    }
115
    
116
    /**
117
     * @inheritdoc
118
     */
119
    protected function updateRule($name, $rule)
120
    {
121
        if ($rule->name !== $name && !$this->supportsCascadeUpdate()) {
122
            $this->db->createCommand()
123
                ->update($this->itemTable, ['rule_name' => $rule->name], ['rule_name' => $name])
124
                ->execute();
125
        }
126
127
        $rule->updatedAt = gmdate('Y-m-d H:i:s');
0 ignored issues
show
Documentation Bug introduced by
The property $updatedAt was declared of type integer, but gmdate('Y-m-d H:i:s') is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
128
129
        $this->db->createCommand()
130
            ->update($this->ruleTable, [
131
                'name' => $rule->name,
132
                'data' => serialize($rule),
133
                'updated_at' => $rule->updatedAt,
134
            ], [
135
                'name' => $name,
136
            ])->execute();
137
138
        $this->invalidateCache();
139
140
        return true;
141
    }
142
    
143
    /**
144
     * Get roles by user.
145
     * @param string|User $userGuid
146
     * @return array
147
     */
148
    public function getRolesByUser($userGuid)
149
    {
150
        if (!isset($userGuid) || $userGuid === '') {
151
            return [];
152
        }
153
        
154
        if ($userGuid instanceof User) {
155
            $userGuid = $userGuid->getGUID();
156
        }
157
158
        $query = (new Query)->select('b.*')
159
            ->from(['a' => $this->assignmentTable, 'b' => $this->itemTable])
160
            ->where('{{a}}.[[item_name]]={{b}}.[[name]]')
161
            ->andWhere(['a.user_guid' => (string) $userGuid])
162
            ->andWhere(['b.type' => Item::TYPE_ROLE]);
163
164
        $roles = [];
165
        foreach ($query->all($this->db) as $row) {
166
            $roles[$row['name']] = $this->populateItem($row);
167
        }
168
        return $roles;
169
    }
170
171
    /**
172
     * Returns all permissions that are directly assigned to user.
173
     * @param string|User $userGuid the user GUID (see [[\rhosocial\user\User::guid]])
174
     * @return Permission[] all direct permissions that the user has. The array is indexed by the permission names.
175
     */
176
    protected function getDirectPermissionsByUser($userGuid)
177
    {
178
        $query = (new Query)->select('b.*')
179
            ->from(['a' => $this->assignmentTable, 'b' => $this->itemTable])
180
            ->where('{{a}}.[[item_name]]={{b}}.[[name]]')
181
            ->andWhere(['a.user_guid' => (string) $userGuid])
182
            ->andWhere(['b.type' => Item::TYPE_PERMISSION]);
183
184
        $permissions = [];
185
        foreach ($query->all($this->db) as $row) {
186
            $permissions[$row['name']] = $this->populateItem($row);
187
        }
188
        return $permissions;
189
    }
190
191
    /**
192
     * Returns all permissions that the user inherits from the roles assigned to him.
193
     * @param string|User $userGuid the user GUID (see [[\rhosocial\user\User::guid]])
194
     * @return Permission[] all inherited permissions that the user has. The array is indexed by the permission names.
195
     */
196
    protected function getInheritedPermissionsByUser($userGuid)
197
    {
198
        $query = (new Query)->select('item_name')
199
            ->from($this->assignmentTable)
200
            ->where(['user_guid' => (string) $userGuid]);
201
202
        $childrenList = $this->getChildrenList();
203
        $result = [];
204
        foreach ($query->column($this->db) as $roleName) {
205
            $this->getChildrenRecursive($roleName, $childrenList, $result);
206
        }
207
208
        if (empty($result)) {
209
            return [];
210
        }
211
212
        $query = (new Query)->from($this->itemTable)->where([
213
            'type' => Item::TYPE_PERMISSION,
214
            'name' => array_keys($result),
215
        ]);
216
        $permissions = [];
217
        foreach ($query->all($this->db) as $row) {
218
            $permissions[$row['name']] = $this->populateItem($row);
219
        }
220
        return $permissions;
221
    }
222
223
    /**
224
     * @inheritdoc
225
     */
226
    public function getAssignment($roleName, $userGuid)
227
    {
228
        if (empty($userGuid)) {
229
            return null;
230
        }
231
        
232
        if ($userGuid instanceof User) {
233
            $userGuid = $userGuid->getGUID();
234
        }
235
236
        $row = (new Query)->from($this->assignmentTable)
237
            ->where(['user_guid' => (string) $userGuid, 'item_name' => $roleName])
238
            ->one($this->db);
239
240
        if ($row === false) {
241
            return null;
242
        }
243
        
244
        $assignment = new Assignment([
245
            'userGuid' => $row['user_guid'],
246
            'roleName' => $row['item_name'],
247
            'createdAt' => $row['created_at'],
248
            'failedAt' => $row['failed_at'],
249
        ]);
250
        
251
        if ($this->revokeFailedAssignment($assignment)) {
252
            return null;
253
        }
254
255
        return $assignment;
256
    }
257
    
258
    /**
259
     * Revoke failed assignment.
260
     * If assignment's `failedAt` attribute is `null`, false will be given directly.
261
     * @param Assignment $assignment
262
     * @return boolean
263
     */
264
    protected function revokeFailedAssignment(Assignment $assignment)
265
    {
266
        if ($assignment->failedAt === null) {
267
            return false;
268
        }
269
        if (strtotime($assignment->failedAt) < strtotime(gmdate('Y-m-d H:i:s'))) {
270
            $role = $this->getRole($assignment->roleName);
271
            if (!$role) {
272
                return true;
273
            }
274
            $this->revoke($role->name, $assignment->userGuid);
0 ignored issues
show
$role->name is of type string, but the function expects a object<yii\rbac\Role>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
It seems like $assignment->userGuid can also be of type object<rhosocial\user\User>; however, rhosocial\user\rbac\DbManager::revoke() does only seem to accept string|integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
275
            return true;
276
        }
277
        return false;
278
    }
279
280
    /**
281
     * @inheritdoc
282
     */
283
    public function getAssignments($userGuid)
284
    {
285
        if (empty($userGuid)) {
286
            return [];
287
        }
288
        
289
        if ($userGuid instanceof User) {
290
            $userGuid = $userGuid->getGUID();
291
        }
292
293
        $query = (new Query)
294
            ->from($this->assignmentTable)
295
            ->where(['user_guid' => (string) $userGuid]);
296
297
        $assignments = [];
298
        foreach ($query->all($this->db) as $row) {
299
            $assignment = new Assignment([
300
                'userGuid' => $row['user_guid'],
301
                'roleName' => $row['item_name'],
302
                'createdAt' => $row['created_at'],
303
                'failedAt' => $row['failed_at'],
304
            ]);
305
            if ($this->revokeFailedAssignment($assignment)) {
306
                continue;
307
            }
308
            $assignments[$row['item_name']] = $assignment;
309
        }
310
311
        return $assignments;
312
    }
313
314
    /**
315
     * @inheritdoc
316
     */
317
    public function assign($role, $userGuid, $failedAt = null)
318
    {
319
        if ($role instanceof Item) {
320
            $role = $role->name;
321
        }
322
        $assignment = new Assignment([
323
            'userGuid' => $userGuid,
324
            'roleName' => $role,
325
            'createdAt' => gmdate('Y-m-d H:i:s'),
326
            'failedAt' => empty($failedAt) ? null : $failedAt,
327
        ]);
328
329
        $this->db->createCommand()
330
            ->insert($this->assignmentTable, [
331
                'user_guid' => $assignment->userGuid,
332
                'item_name' => $assignment->roleName,
333
                'created_at' => $assignment->createdAt,
334
                'failed_at' => $assignment->failedAt,
335
            ])->execute();
336
337
        return $assignment;
338
    }
339
340
    /**
341
     * @inheritdoc
342
     */
343
    public function revoke($role, $userGuid)
344
    {
345
        if (empty($userGuid)) {
346
            return false;
347
        }
348
        
349
        if ($userGuid instanceof User) {
350
            $userGuid = $userGuid->getGUID();
351
        }
352
353
        if ($role instanceof Item) {
354
            $role = $role->name;
355
        }
356
357
        return $this->db->createCommand()
358
            ->delete($this->assignmentTable, ['user_guid' => (string) $userGuid, 'item_name' => $role])
359
            ->execute() > 0;
360
    }
361
362
    /**
363
     * @inheritdoc
364
     */
365
    public function revokeAll($userGuid)
366
    {
367
        if (empty($userGuid)) {
368
            return false;
369
        }
370
        
371
        if ($userGuid instanceof User) {
372
            $userGuid = $userGuid->getGUID();
373
        }
374
375
        return $this->db->createCommand()
376
            ->delete($this->assignmentTable, ['user_guid' => (string) $userGuid])
377
            ->execute() > 0;
378
    }
379
380
    /**
381
     * Returns all role assignment information for the specified role.
382
     * @param string $roleName
383
     * @return Assignment[] the assignments. An empty array will be
384
     * returned if role is not assigned to any user.
385
     * @since 2.0.7
386
     */
387
    public function getUserGuidsByRole($roleName)
388
    {
389
        if (empty($roleName)) {
390
            return [];
391
        }
392
393
        return (new Query)->select('[[user_guid]]')
394
            ->from($this->assignmentTable)
395
            ->where(['item_name' => $roleName])->column($this->db);
396
    }
397
398
    /**
399
     * Populates an auth item with the data fetched from database
400
     * @param array $row the data from the auth item table
401
     * @return Item the populated auth item instance (either Role or Permission)
402
     */
403
    protected function populateItem($row)
404
    {
405
        $class = $row['type'] == Item::TYPE_PERMISSION ? Permission::class : Role::class;
406
407
        if (!isset($row['data']) || ($data = @unserialize($row['data'])) === false) {
408
            $data = null;
409
        }
410
411
        return new $class([
412
            'name' => $row['name'],
413
            'type' => $row['type'],
414
            'description' => $row['description'],
415
            'ruleName' => $row['rule_name'],
416
            'data' => $data,
417
            'color' => $row['color'],
418
            'createdAt' => $row['created_at'],
419
            'updatedAt' => $row['updated_at'],
420
        ]);
421
    }
422
423
    /**
424
     * @inheritdoc
425
     */
426
    public function getChildren($name)
427
    {
428
        $query = (new Query)
429
            ->select(['name', 'type', 'description', 'rule_name', 'data', 'color', 'created_at', 'updated_at'])
430
            ->from([$this->itemTable, $this->itemChildTable])
431
            ->where(['parent' => $name, 'name' => new Expression('[[child]]')]);
432
433
        $children = [];
434
        foreach ($query->all($this->db) as $row) {
435
            $children[$row['name']] = $this->populateItem($row);
436
        }
437
438
        return $children;
439
    }
440
}
441