Passed
Push — master ( 409c3f...e5371a )
by Andreas
09:22
created

privileges::get_privileges()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.2559

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 8
ccs 3
cts 5
cp 0.6
crap 2.2559
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package midcom.dba
4
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
namespace midcom\dba;
10
11
use midcom;
12
use midcom_error;
13
use midcom_core_privilege;
14
15
/**
16
 * midcom privileges support
17
 *
18
 * These calls operate only on the privileges of the given object. They do not do any merging
19
 * whatsoever, this is the job of the ACL framework itself (midcom_services_auth_acl).
20
 *
21
 * Unsetting a privilege does not deny it, but clears the privilege specification on the current
22
 * object and sets it to INHERIT internally. As you might have guessed, if you want to clear
23
 * all privileges on a given object, call unset_all_privileges() on the DBA object in question.
24
 *
25
 * @package midcom.dba
26
 */
27
trait privileges
28
{
29
    /**
30
     * Read all privilege records and return them accordingly.
31
     *
32
     * You need privilege access to get this information (midgard:read (tested during
33
     * construction) and midgard:privileges) otherwise, the call will fail.
34
     *
35
     * @return midcom_core_privilege[] A list of privilege objects or false on failure.
36
     */
37 1
    public function get_privileges()
38
    {
39 1
        if (!$this->can_do('midgard:privileges')) {
0 ignored issues
show
Bug introduced by
It seems like can_do() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

39
        if (!$this->/** @scrutinizer ignore-call */ can_do('midgard:privileges')) {
Loading history...
40
            debug_add('Could not query the privileges, permission denied.', MIDCOM_LOG_WARN);
41
            return false;
42
        }
43
44 1
        return midcom_core_privilege::get_all_privileges($this->guid);
45
    }
46
47
    /**
48
     * Set a privilege on an object.
49
     *
50
     * This requires both midgard:update and midgard:privileges.
51
     *
52
     * You can either pass a ready made privilege record or a privilege/assignee/value
53
     * combination suitable for usage with create_new_privilege_object() (see there).
54
     *
55
     * @param mixed $privilege Either the full privilege object (midcom_core_privilege) to set or the name of the privilege (string).
56
     *     If the name was specified, the other parameters must be specified as well.
57
     * @param mixed $assignee A valid assignee suitable for midcom_core_privilege::set_privilege(). This defaults to the currently
58
     *     active user if authenticated or to 'EVERYONE' otherwise (invalid if $privilege is a midcom_core_privilege).
59
     * @param int $value The privilege value, this defaults to MIDCOM_PRIVILEGE_ALLOW (invalid if $privilege is a midcom_core_privilege).
60
     * @param string $classname An optional class name to which a SELF privilege gets restricted to. Only valid for SELF privileges
61
     *     (invalid if $privilege is a midcom_core_privilege).
62
     * @return boolean Indicating success.
63
     * @see \midcom_services_auth
64
     */
65 124
    public function set_privilege($privilege, $assignee = null, int $value = MIDCOM_PRIVILEGE_ALLOW, string $classname = '') : bool
66
    {
67 124
        if (   !$this->can_do('midgard:update')
68 124
            || !$this->can_do('midgard:privileges')) {
69
            debug_add("Failed to set a privilege, midgard:update or midgard:privileges on " . static::class . " {$this->guid} not granted for the current user.",
70
            MIDCOM_LOG_ERROR);
71
            return false;
72
        }
73
74 124
        if ($privilege instanceof midcom_core_privilege) {
75
            return $privilege->store();
76
        }
77 124
        if (is_string($privilege)) {
78 124
            $tmp = $this->create_new_privilege_object($privilege, $assignee, $value, $classname);
79 124
            return $tmp->store();
80
        }
81
        throw new midcom_error('Unknown $privilege argument type');
82
    }
83
84
    /**
85
     * Unset a privilege on an object (e.g. set it to INHERIT).
86
     *
87
     * @param mixed $privilege Either the full privilege object (midcom_core_privilege) to set or the name of the privilege (string).
88
     *     If the name was specified, the other parameters must be specified as well.
89
     * @param mixed $assignee A valid assignee suitable for midcom_core_privilege::set_privilege(). This defaults to the currently
90
     *     active user if authenticated or to 'EVERYONE' otherwise (invalid if $privilege is a midcom_core_privilege).
91
     * @param string $classname An optional class name to which a SELF privilege gets restricted to. Only valid for SELF privileges
92
     *     (invalid if $privilege is a midcom_core_privilege).
93
     * @return boolean Indicating Success.
94
     */
95 7
    public function unset_privilege($privilege, $assignee = null, string $classname = '') : bool
96
    {
97 7
        if (   !$this->can_do('midgard:update')
98 7
            || !$this->can_do('midgard:privileges')) {
99
            debug_add("Failed to unset a privilege, midgard:update or midgard:privileges on " . static::class . " {$this->guid} not granted for the current user.",
100
            MIDCOM_LOG_ERROR);
101
            return false;
102
        }
103
104 7
        if ($privilege instanceof midcom_core_privilege) {
105
            $priv = $privilege;
106 7
        } elseif (is_string($privilege)) {
107 7
            $assignee ??= midcom::get()->auth->user ?: 'EVERYONE';
108 7
            $priv = $this->get_privilege($privilege, $assignee, $classname);
109 7
            if (!$priv) {
110 7
                return false;
111
            }
112
        } else {
113
            throw new midcom_error('Invalid arguments for unset_privilege. See debug level log for details.');
114
        }
115
116 7
        return $priv->drop();
117
    }
118
119
    /**
120
     * Looks up a privilege by its parameters.
121
     *
122
     * @param mixed $assignee Either a valid magic assignee (SELF, EVERYONE, USERS, ANONYMOUS), a midcom_core_user or a
123
     *     midcom_core_group object or subtype thereof.
124
     * @param string $classname An optional class name to which a SELF privilege is restricted to.
125
     */
126 12
    public function get_privilege(string $privilege, $assignee, string $classname = '')
127
    {
128 12
        if (!$this->can_do('midgard:privileges')) {
129
            debug_add("Failed to get a privilege, midgard:update or midgard:privileges on " . static::class . " {$this->guid} not granted for the current user.",
130
            MIDCOM_LOG_ERROR);
131
            return false;
132
        }
133
134 12
        if (is_object($assignee)) {
135
            $assignee = $assignee->id;
136
        }
137 12
        return midcom_core_privilege::get_privilege($this, $privilege, $assignee, $classname);
138
    }
139
140
    /**
141
     * Unsets all privileges
142
     *
143
     * @return boolean Indicating success.
144
     */
145
    public function unset_all_privileges() : bool
146
    {
147
        $privileges = $this->get_privileges();
148
        if (!$privileges) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $privileges of type midcom_core_privilege[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
149
            debug_add('Failed to access the privileges. See above for details.', MIDCOM_LOG_ERROR);
150
            return false;
151
        }
152
        foreach ($privileges as $privilege) {
153
            if ($this->unset_privilege($privilege)) {
154
                debug_add('Failed to drop a privilege record, see debug log for more information, aborting.', MIDCOM_LOG_WARN);
155
                return false;
156
            }
157
        }
158
        return true;
159
    }
160
161
    /**
162
     * Create a new privilege object. The privilege will
163
     * be initialized with the values given in the arguments, as outlined below.
164
     *
165
     * This call requires the <i>midgard:privileges</i> privilege.
166
     *
167
     * @param mixed $assignee A valid assignee suitable for midcom_core_privilege::set_privilege(). This defaults to the currently
168
     *     active user if authenticated or to 'EVERYONE' otherwise.
169
     * @param int $value The privilege value, this defaults to MIDCOM_PRIVILEGE_ALLOW.
170
     * @param string $classname An optional class name to which a SELF privilege gets restricted to. Only valid for SELF privileges.
171
     */
172 124
    public function create_new_privilege_object(string $name, $assignee = null, int $value = MIDCOM_PRIVILEGE_ALLOW, string $classname = '') : midcom_core_privilege
173
    {
174 124
        if (!$this->can_do('midgard:privileges')) {
175
            throw new midcom_error('Could not create a new privilege, permission denied.');
176
        }
177
178 124
        if ($assignee === null) {
179
            $assignee = midcom::get()->auth->user ?: 'EVERYONE';
180
        }
181
182 124
        $privilege = new midcom_core_privilege();
183 124
        if (!$privilege->set_assignee($assignee)) {
184
            throw new midcom_error('Failed to set the assignee');
185
        }
186 124
        $privilege->set_object($this);
187 124
        $privilege->privilegename = $name;
188 124
        $privilege->value = $value;
189 124
        $privilege->classname = $classname;
190 124
        if (!$privilege->validate()) {
191
            throw new midcom_error('Failed to validate the newly created privilege.');
192
        }
193 124
        return $privilege;
194
    }
195
}
196