Issues (806)

src/midcom/dba/privileges.php (2 issues)

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
use midcom_core_user;
15
use midcom_core_group;
16
17
/**
18
 * midcom privileges support
19
 *
20
 * These calls operate only on the privileges of the given object. They do not do any merging
21
 * whatsoever, this is the job of the ACL framework itself (midcom_services_auth_acl).
22
 *
23
 * Unsetting a privilege does not deny it, but clears the privilege specification on the current
24
 * object and sets it to INHERIT internally. As you might have guessed, if you want to clear
25
 * all privileges on a given object, call unset_all_privileges() on the DBA object in question.
26
 *
27
 * @package midcom.dba
28
 */
29
trait privileges
30
{
31
    /**
32
     * Read all privilege records and return them accordingly.
33
     *
34
     * You need privilege access to get this information (midgard:read (tested during
35
     * construction) and midgard:privileges) otherwise, the call will fail.
36
     *
37
     * @return midcom_core_privilege[] A list of privilege objects or false on failure.
38
     */
39 1
    public function get_privileges()
40
    {
41 1
        if (!$this->can_do('midgard:privileges')) {
0 ignored issues
show
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

41
        if (!$this->/** @scrutinizer ignore-call */ can_do('midgard:privileges')) {
Loading history...
42
            debug_add('Could not query the privileges, permission denied.', MIDCOM_LOG_WARN);
43
            return false;
44
        }
45
46 1
        return midcom_core_privilege::get_all_privileges($this->guid);
47
    }
48
49
    /**
50
     * Set a privilege on an object.
51
     *
52
     * This requires both midgard:update and midgard:privileges.
53
     *
54
     * You can either pass a ready made privilege record or a privilege/assignee/value
55
     * combination suitable for usage with create_new_privilege_object() (see there).
56
     *
57
     * @param mixed $privilege Either the full privilege object (midcom_core_privilege) to set or the name of the privilege (string).
58
     *     If the name was specified, the other parameters must be specified as well.
59
     * @param mixed $assignee A valid assignee suitable for midcom_core_privilege::set_privilege(). This defaults to the currently
60
     *     active user if authenticated or to 'EVERYONE' otherwise (invalid if $privilege is a midcom_core_privilege).
61
     * @param int $value The privilege value, this defaults to MIDCOM_PRIVILEGE_ALLOW (invalid if $privilege is a midcom_core_privilege).
62
     * @param string $classname An optional class name to which a SELF privilege gets restricted to. Only valid for SELF privileges
63
     *     (invalid if $privilege is a midcom_core_privilege).
64
     * @return boolean Indicating success.
65
     * @see \midcom_services_auth
66
     */
67 125
    public function set_privilege($privilege, $assignee = null, int $value = MIDCOM_PRIVILEGE_ALLOW, string $classname = '') : bool
68
    {
69 125
        if (   !$this->can_do('midgard:update')
70 125
            || !$this->can_do('midgard:privileges')) {
71
            debug_add("Failed to set a privilege, midgard:update or midgard:privileges on " . static::class . " {$this->guid} not granted for the current user.",
72
            MIDCOM_LOG_ERROR);
73
            return false;
74
        }
75
76 125
        if ($privilege instanceof midcom_core_privilege) {
77
            return $privilege->store();
78
        }
79 125
        if (is_string($privilege)) {
80 125
            $tmp = $this->create_new_privilege_object($privilege, $assignee, $value, $classname);
81 125
            return $tmp->store();
82
        }
83
        throw new midcom_error('Unknown $privilege argument type');
84
    }
85
86
    /**
87
     * Unset a privilege on an object (e.g. set it to INHERIT).
88
     *
89
     * @param mixed $privilege Either the full privilege object (midcom_core_privilege) to set or the name of the privilege (string).
90
     *     If the name was specified, the other parameters must be specified as well.
91
     * @param mixed $assignee A valid assignee suitable for midcom_core_privilege::set_privilege(). This defaults to the currently
92
     *     active user if authenticated or to 'EVERYONE' otherwise (invalid if $privilege is a midcom_core_privilege).
93
     * @param string $classname An optional class name to which a SELF privilege gets restricted to. Only valid for SELF privileges
94
     *     (invalid if $privilege is a midcom_core_privilege).
95
     * @return boolean Indicating Success.
96
     */
97 8
    public function unset_privilege($privilege, $assignee = null, string $classname = '') : bool
98
    {
99 8
        if (   !$this->can_do('midgard:update')
100 8
            || !$this->can_do('midgard:privileges')) {
101
            debug_add("Failed to unset a privilege, midgard:update or midgard:privileges on " . static::class . " {$this->guid} not granted for the current user.",
102
            MIDCOM_LOG_ERROR);
103
            return false;
104
        }
105
106 8
        if ($privilege instanceof midcom_core_privilege) {
107
            $priv = $privilege;
108 8
        } elseif (is_string($privilege)) {
109 8
            $assignee ??= midcom::get()->auth->user ?: 'EVERYONE';
110 8
            $priv = $this->get_privilege($privilege, $assignee, $classname);
111 8
            if (!$priv) {
112 8
                return false;
113
            }
114
        } else {
115
            throw new midcom_error('Invalid arguments for unset_privilege. See debug level log for details.');
116
        }
117
118 8
        return $priv->drop();
119
    }
120
121
    /**
122
     * Looks up a privilege by its parameters.
123
     *
124
     * @param mixed $assignee Either a valid magic assignee (SELF, EVERYONE, USERS, ANONYMOUS), a midcom_core_user or a
125
     *     midcom_core_group object or subtype thereof.
126
     * @param string $classname An optional class name to which a SELF privilege is restricted to.
127
     */
128 13
    public function get_privilege(string $privilege, midcom_core_user|midcom_core_group|string $assignee, string $classname = '')
129
    {
130 13
        if (!$this->can_do('midgard:privileges')) {
131
            debug_add("Failed to get a privilege, midgard:update or midgard:privileges on " . static::class . " {$this->guid} not granted for the current user.",
132
            MIDCOM_LOG_ERROR);
133
            return false;
134
        }
135
136 13
        if (is_object($assignee)) {
137
            $assignee = $assignee->id;
138
        }
139 13
        return midcom_core_privilege::get_privilege($this, $privilege, $assignee, $classname);
140
    }
141
142
    /**
143
     * Unsets all privileges
144
     *
145
     * @return boolean Indicating success.
146
     */
147
    public function unset_all_privileges() : bool
148
    {
149
        $privileges = $this->get_privileges();
150
        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...
151
            debug_add('Failed to access the privileges. See above for details.', MIDCOM_LOG_ERROR);
152
            return false;
153
        }
154
        foreach ($privileges as $privilege) {
155
            if ($this->unset_privilege($privilege)) {
156
                debug_add('Failed to drop a privilege record, see debug log for more information, aborting.', MIDCOM_LOG_WARN);
157
                return false;
158
            }
159
        }
160
        return true;
161
    }
162
163
    /**
164
     * Create a new privilege object. The privilege will
165
     * be initialized with the values given in the arguments, as outlined below.
166
     *
167
     * This call requires the <i>midgard:privileges</i> privilege.
168
     *
169
     * @param mixed $assignee A valid assignee suitable for midcom_core_privilege::set_privilege(). This defaults to the currently
170
     *     active user if authenticated or to 'EVERYONE' otherwise.
171
     * @param int $value The privilege value, this defaults to MIDCOM_PRIVILEGE_ALLOW.
172
     * @param string $classname An optional class name to which a SELF privilege gets restricted to. Only valid for SELF privileges.
173
     */
174 125
    public function create_new_privilege_object(string $name, $assignee = null, int $value = MIDCOM_PRIVILEGE_ALLOW, string $classname = '') : midcom_core_privilege
175
    {
176 125
        if (!$this->can_do('midgard:privileges')) {
177
            throw new midcom_error('Could not create a new privilege, permission denied.');
178
        }
179
180 125
        $assignee ??= midcom::get()->auth->user ?: 'EVERYONE';
181
182 125
        $privilege = new midcom_core_privilege();
183 125
        if (!$privilege->set_assignee($assignee)) {
184
            throw new midcom_error('Failed to set the assignee');
185
        }
186 125
        $privilege->set_object($this);
187 125
        $privilege->privilegename = $name;
188 125
        $privilege->value = $value;
189 125
        $privilege->classname = $classname;
190 125
        if (!$privilege->validate()) {
191
            throw new midcom_error('Failed to validate the newly created privilege.');
192
        }
193 125
        return $privilege;
194
    }
195
}
196