Completed
Push — master ( 770316...74fc07 )
by Jeroen
09:08 queued 02:44
created

Helper/Security/Acl/AclNativeHelper.php (1 issue)

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
namespace Kunstmaan\AdminBundle\Helper\Security\Acl;
4
5
use Doctrine\DBAL\Query\QueryBuilder;
6
use Doctrine\ORM\EntityManager;
7
use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\MaskBuilder;
8
use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionDefinition;
9
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
10
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
11
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
12
use Symfony\Component\Security\Core\Role\RoleInterface;
13
14
/**
15
 * AclHelper is a helper class to help setting the permissions when querying using native queries
16
 *
17
 * @see https://gist.github.com/1363377
18
 */
19
class AclNativeHelper
20
{
21
    /**
22
     * @var EntityManager
23
     */
24
    private $em = null;
25
26
    /**
27
     * @var TokenStorageInterface
28
     */
29
    private $tokenStorage = null;
30
31
    /**
32
     * @var RoleHierarchyInterface
33
     */
34
    private $roleHierarchy = null;
35
36
    /**
37
     * Constructor.
38
     *
39
     * @param EntityManager          $em           The entity manager
40
     * @param TokenStorageInterface  $tokenStorage The security context
41
     * @param RoleHierarchyInterface $rh           The role hierarchies
42
     */
43 1
    public function __construct(EntityManager $em, TokenStorageInterface $tokenStorage, RoleHierarchyInterface $rh)
44
    {
45 1
        $this->em = $em;
46 1
        $this->tokenStorage = $tokenStorage;
47 1
        $this->roleHierarchy = $rh;
48 1
    }
49
50
    /**
51
     * Apply the ACL constraints to the specified query builder, using the permission definition
52
     *
53
     * @param QueryBuilder         $queryBuilder  The query builder
54
     * @param PermissionDefinition $permissionDef The permission definition
55
     *
56
     * @return QueryBuilder
57
     */
58
    public function apply(QueryBuilder $queryBuilder, PermissionDefinition $permissionDef)
59
    {
60
        $aclConnection = $this->em->getConnection();
61
62
        $databasePrefix = is_file($aclConnection->getDatabase()) ? '' : $aclConnection->getDatabase().'.';
63
        $rootEntity = $permissionDef->getEntity();
64
        $linkAlias = $permissionDef->getAlias();
65
        // Only tables with a single ID PK are currently supported
66
        $linkField = $this->em->getClassMetadata($rootEntity)->getSingleIdentifierColumnName();
67
68
        $rootEntity = '"' . str_replace('\\', '\\\\', $rootEntity) . '"';
69
        $query = $queryBuilder;
70
71
        $builder = new MaskBuilder();
72 View Code Duplication
        foreach ($permissionDef->getPermissions() as $permission) {
73
            $mask = constant(get_class($builder) . '::MASK_' . strtoupper($permission));
74
            $builder->add($mask);
75
        }
76
        $mask = $builder->get();
77
78
        /* @var $token TokenInterface */
79
        $token = $this->tokenStorage->getToken();
80
        $userRoles = array();
81 View Code Duplication
        if (!is_null($token)) {
82
            $user = $token->getUser();
83
            $userRoles = $this->roleHierarchy->getReachableRoles($token->getRoles());
84
        }
85
86
        // Security context does not provide anonymous role automatically.
87
        $uR = array('"IS_AUTHENTICATED_ANONYMOUSLY"');
88
89
        /* @var $role RoleInterface */
90 View Code Duplication
        foreach ($userRoles as $role) {
91
            // The reason we ignore this is because by default FOSUserBundle adds ROLE_USER for every user
92
            if ($role->getRole() !== 'ROLE_USER') {
93
                $uR[] = '"' . $role->getRole() . '"';
94
            }
95
        }
96
        $uR = array_unique($uR);
97
        $inString = implode(' OR s.identifier = ', (array) $uR);
98
99 View Code Duplication
        if (is_object($user)) {
100
            $inString .= ' OR s.identifier = "' . str_replace(
101
                    '\\',
102
                    '\\\\',
103
                    get_class($user)
0 ignored issues
show
The variable $user does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
104
                ) . '-' . $user->getUserName() . '"';
105
        }
106
107
        $joinTableQuery = <<<SELECTQUERY
108
SELECT DISTINCT o.object_identifier as id FROM {$databasePrefix}acl_object_identities as o
109
INNER JOIN {$databasePrefix}acl_classes c ON c.id = o.class_id
110
LEFT JOIN {$databasePrefix}acl_entries e ON (
111
    e.class_id = o.class_id AND (e.object_identity_id = o.id
112
    OR {$aclConnection->getDatabasePlatform()->getIsNullExpression('e.object_identity_id')})
113
)
114
LEFT JOIN {$databasePrefix}acl_security_identities s ON (
115
s.id = e.security_identity_id
116
)
117
WHERE c.class_type = {$rootEntity}
118
AND (s.identifier = {$inString})
119
AND e.mask & {$mask} > 0
120
SELECTQUERY;
121
122
        $query->join($linkAlias, '(' . $joinTableQuery . ')', 'perms_', 'perms_.id = ' . $linkAlias . '.' . $linkField);
123
124
        return $query;
125
    }
126
127
    /**
128
     * @return null|TokenStorageInterface
129
     */
130 1
    public function getTokenStorage()
131
    {
132 1
        return $this->tokenStorage;
133
    }
134
}
135