Passed
Push — master ( f31336...47fe76 )
by Jan
05:11
created

ElementPermissionListener   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 74
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 24
dl 0
loc 74
rs 10
c 0
b 0
f 0
wmc 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A preUpdateHandler() 0 24 5
A postLoadHandler() 0 22 4
A __construct() 0 3 1
1
<?php
2
/**
3
 *
4
 * part-db version 0.1
5
 * Copyright (C) 2005 Christoph Lechner
6
 * http://www.cl-projects.de/
7
 *
8
 * part-db version 0.2+
9
 * Copyright (C) 2009 K. Jacobs and others (see authors.php)
10
 * http://code.google.com/p/part-db/
11
 *
12
 * Part-DB Version 0.4+
13
 * Copyright (C) 2016 - 2019 Jan Böhmer
14
 * https://github.com/jbtronics
15
 *
16
 * This program is free software; you can redistribute it and/or
17
 * modify it under the terms of the GNU General Public License
18
 * as published by the Free Software Foundation; either version 2
19
 * of the License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
29
 *
30
 */
31
32
namespace App\Security\EntityListeners;
33
34
35
use App\Security\Annotations\ColumnSecurity;
36
use App\Entity\DBElement;
37
use Doctrine\Common\Annotations\AnnotationReader;
38
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
39
use Doctrine\ORM\Event\PreUpdateEventArgs;
40
use Doctrine\ORM\Mapping\PostLoad;
41
use Doctrine\ORM\Mapping\PreUpdate;
42
use ReflectionClass;
43
use Symfony\Component\Security\Core\Security;
44
45
/**
46
 * The purpose of this class is to hook into the doctrine entity lifecycle and restrict access to entity informations
47
 * configured by ColoumnSecurity Annotation.
48
 *
49
 * If a user does not have access to an coloumn, it will be filled, with a placeholder, after doctrine loading is finished.
50
 * The edit process is also catched, so that these placeholders, does not get saved to database.
51
 * @package App\EntityListeners
52
 */
53
class ElementPermissionListener
54
{
55
    protected $security;
56
57
    public function __construct(Security $security)
58
    {
59
        $this->security = $security;
60
    }
61
62
63
    /**
64
     * @PostLoad
65
     *
66
     * This function is called after doctrine filled, the entity properties with db values.
67
     * We use this, to check if the user is allowed to access these properties, and if not, we write a placeholder
68
     * into the element properties, so that a user only gets non sensitve data.
69
     *
70
     */
71
    public function postLoadHandler(DBElement $element, LifecycleEventArgs $event)
0 ignored issues
show
Unused Code introduced by
The parameter $event 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

71
    public function postLoadHandler(DBElement $element, /** @scrutinizer ignore-unused */ LifecycleEventArgs $event)

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...
72
    {
73
        //Read Annotations and properties.
74
        $reflectionClass = new ReflectionClass($element);
75
        $properties = $reflectionClass->getProperties();
76
        $reader = new AnnotationReader();
77
78
        foreach($properties as $property)
79
        {
80
            /**
81
             * @var ColumnSecurity $annotation
82
             */
83
            $annotation = $reader->getPropertyAnnotation($property,
84
                ColumnSecurity::class);
85
86
            if($annotation !== null)
87
            {
88
                //Check if user is allowed to read info, otherwise apply placeholder
89
                if(!$this->security->isGranted($annotation->getReadOperationName(), $element))
90
                {
91
                    $property->setAccessible(true);
92
                    $property->setValue($element, $annotation->getPlaceholder());
93
                }
94
            }
95
        }
96
    }
97
98
    /**
99
     * @PreUpdate
100
     * This function is called before Doctrine saves the property values to the database.
101
     * We use this function to revert the changes made in postLoadHandler(), so nothing gets changed persistently.
102
     */
103
    public function preUpdateHandler(DBElement $element, PreUpdateEventArgs $event)
104
    {
105
        $reflectionClass = new ReflectionClass($element);
106
        $properties = $reflectionClass->getProperties();
107
        $reader = new AnnotationReader();
108
109
        foreach($properties as $property)
110
        {
111
            /**
112
             * @var ColumnSecurity $annotation
113
             */
114
            $annotation = $reader->getPropertyAnnotation($property,
115
                ColumnSecurity::class);
116
117
            if($annotation !== null)
118
            {
119
                $field_name = $property->getName();
120
121
                //Check if user is allowed to edit info, otherwise overwrite the new value
122
                // so that nothing is changed in the DB.
123
                if($event->hasChangedField($field_name) &&
124
                    !$this->security->isGranted($annotation->getEditOperationName(), $element))
125
                {
126
                    $event->setNewValue($field_name, $event->getOldValue($field_name));
127
                }
128
            }
129
        }
130
    }
131
132
133
}