Completed
Branch master (024767)
by Henry Stivens
01:51
created

Acl   C

Complexity

Total Complexity 66

Size/Duplication

Total Lines 404
Duplicated Lines 19.8 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 80
loc 404
rs 5.7474
c 0
b 0
f 0
wmc 66
lcom 1
cbo 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Acl often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Acl, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * KumbiaPHP web & app Framework
4
 *
5
 * LICENSE
6
 *
7
 * This source file is subject to the new BSD license that is bundled
8
 * with this package in the file LICENSE.txt.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://wiki.kumbiaphp.com/Licencia
11
 * If you did not receive a copy of the license and are unable to
12
 * obtain it through the world-wide-web, please send an email
13
 * to [email protected] so we can send you a copy immediately.
14
 *
15
 * @category   Kumbia
16
 * @package    Acl
17
 * @copyright  Copyright (c) 2005 - 2017 Kumbia Team (http://www.kumbiaphp.com)
18
 * @license    http://wiki.kumbiaphp.com/Licencia     New BSD License
19
 */
20
/**
21
 * @see AclRole
22
 */
23
include __DIR__ .'/role/role.php';
24
25
/**
26
 * @see AclResource
27
 */
28
include __DIR__ .'/resource/resource.php';
29
30
/**
31
 * Listas ACL (Access Control List)
32
 *
33
 * La Lista de Control de Acceso o ACLs (del ingles, Access Control List)
34
 * es un concepto de seguridad informatica usado para fomentar la separacion
35
 * de privilegios. Es una forma de determinar los permisos de acceso apropiados
36
 * a un determinado objeto, dependiendo de ciertos aspectos del proceso
37
 * que hace el pedido.
38
 *
39
 * Cada lista ACL contiene una lista de Roles, unos resources y unas acciones de
40
 * acceso;
41
 *
42
 * $roles = Lista de Objetos Acl_Role de Roles de la Lista
43
 * $resources = Lista de Objetos Acl_Resource que van a ser controlados
44
 * $access = Contiene la lista de acceso
45
 * $role_inherits = Contiene la lista de roles que son heradados por otros
46
 * $resource_names = Nombres de Resources
47
 * $roles_names = Nombres de Resources
48
 *
49
 * @category   Kumbia
50
 * @package    Acl
51
 * @deprecated 1.0 use ACL2
52
 */
53
class Acl {
54
55
    /**
56
     * Nombres de Roles en la lista ACL
57
     *
58
     * @var array
59
     */
60
    private $roles_names = array();
61
    /**
62
     * Objetos Roles en lista ACL
63
     *
64
     * @var array
65
     */
66
    private $roles = array();
67
    /**
68
     * Objetos Resources en la lista ACL
69
     *
70
     * @var array
71
     */
72
    private $resources = array();
73
    /**
74
     * Permisos de la Lista de Acceso
75
     *
76
     * @var array
77
     */
78
    public $access = array();
79
    /**
80
     * Herencia entre Roles
81
     *
82
     * @var array
83
     */
84
    private $role_inherits = array();
85
    /**
86
     * Array de Nombres de Recursos
87
     *
88
     * @var array
89
     */
90
    private $resources_names = array('*');
91
    /**
92
     * Lista ACL de permisos
93
     *
94
     * @var array
95
     */
96
    private $access_list = array('*' => array('*'));
97
98
    /**
99
     * Agrega un Rol a la Lista ACL
100
     *
101
     * $roleObject = Objeto de la clase AclRole para agregar a la lista
102
     * $access_inherits = Nombre del Role del cual hereda permisos ó array del grupo
103
     * de perfiles del cual hereda permisos
104
     *
105
     * Ej:
106
     * <code>$acl->add_role(new Acl_Role('administrador'), 'consultor');</code>
107
     *
108
     * @param AclRole $roleObject
109
     * @return false|null
110
     */
111
    public function add_role(AclRole $roleObject, $access_inherits = '') {
112
        if (in_array($roleObject->name, $this->roles_names)) {
113
            return false;
114
        }
115
        $this->roles[]                             = $roleObject;
116
        $this->roles_names[]                       = $roleObject->name;
117
        $this->access[$roleObject->name]['*']['*'] = 'A';
118
        if ($access_inherits) {
119
            $this->add_inherit($roleObject->name, $access_inherits);
120
        }
121
    }
122
123
    /**
124
     * Hace que un rol herede los accesos de otro rol
125
     *
126
     * @param string $role
127
     * @param string $role_to_inherit
128
     */
129
    public function add_inherit($role, $role_to_inherit) {
130
        if (!in_array($role, $this->roles_names)) {
131
            return false;
132
        }
133
        if ($role_to_inherit != '') {
134
            if (is_array($role_to_inherit)) {
135
                foreach ($role_to_inherit as $rol_in) {
136
                    if ($rol_in == $role) {
137
                        return false;
138
                    }
139
                    if (!in_array($rol_in, $this->roles_names)) {
140
                        throw new KumbiaException("El Rol '{$rol_in}' no existe en la lista");
141
142
                    }
143
                    $this->role_inherits[$role][] = $rol_in;
144
                }
145
                $this->rebuild_access_list();
146
            } else {
147
                if ($role_to_inherit == $role) {
148
                    return false;
149
                }
150
                if (!in_array($role_to_inherit, $this->roles_names)) {
151
                    throw new KumbiaException("El Rol '{$role_to_inherit}' no existe en la lista");
152
153
                }
154
                $this->role_inherits[$role][] = $role_to_inherit;
155
                $this->rebuild_access_list();
156
            }
157
        } else {
158
            throw new KumbiaException("Debe especificar un rol a heredar en Acl::add_inherit");
159
160
        }
161
    }
162
163
    /**
164
     *
165
     * Verifica si un rol existe en la lista o no
166
     *
167
     * @param string $role_name
168
     * @return boolean
169
     */
170
    public function is_role($role_name) {
171
        return in_array($role_name, $this->roles_names);
172
    }
173
174
    /**
175
     *
176
     * Verifica si un resource existe en la lista o no
177
     *
178
     * @param string $resource_name
179
     * @return boolean
180
     */
181
    public function is_resource($resource_name) {
182
        return in_array($resource_name, $this->resources_names);
183
    }
184
185
    /**
186
     * Agrega un resource a la Lista ACL
187
     *
188
     * Resource_name puede ser el nombre de un objeto concreto, por ejemplo
189
     * consulta, buscar, insertar, valida etc o una lista de ellos
190
     *
191
     * Ej:
192
     * <code>
193
     * //Agregar un resource a la lista:
194
     * $acl->add_resource(new AclResource('clientes'), 'consulta');
195
     *
196
     * //Agregar Varios resources a la lista:
197
     * $acl->add_resource(new AclResource('clientes'), 'consulta', 'buscar', 'insertar');
198
     * </code>
199
     *
200
     * @param AclResource $resource
201
     * @return boolean|null
202
     */
203
    public function add_resource(AclResource $resource) {
204
        if (!in_array($resource->name, $this->resources)) {
205
            $this->resources[]                  = $resource;
206
            $this->access_list[$resource->name] = array();
207
            $this->resources_names[]            = $resource->name;
208
        }
209
        if (func_num_args() > 1) {
210
            $access_list = func_get_args();
211
            unset($access_list[0]);
212
            $this->add_resource_access($resource->name, $access_list);
213
        }
214
    }
215
216
    /**
217
     * Agrega accesos a un Resource
218
     *
219
     * @param string $resource
220
     * @param $access_list
221
     */
222
    public function add_resource_access($resource, $access_list) {
223
        if (is_array($access_list)) {
224
            foreach ($access_list as $access_name) {
225
                if (!in_array($access_name, $this->access_list[$resource])) {
226
                    $this->access_list[$resource][] = $access_name;
227
                }
228
            }
229
        } else {
230
            if (!in_array($access_list, $this->access_list[$resource])) {
231
                $this->access_list[$resource][] = $access_list;
232
            }
233
        }
234
    }
235
236
    /**
237
     * Elimina un acceso del resorce
238
     *
239
     * @param string $resource
240
     * @param mixed $access_list
241
     */
242
    public function drop_resource_access($resource, $access_list) {
243
        if (is_array($access_list)) {
244
            foreach ($access_list as $access_name) {
245
                if (in_array($access_name, $this->access_list[$resource])) {
246
                    foreach ($this->access_list[$resource] as $i => $access) {
247
                        if ($access == $access_name) {
248
                            unset($this->access_list[$resource][$i]);
249
                        }
250
                    }
251
                }
252
            }
253
        } else {
254
            if (in_array($access_list, $this->access_list[$resource])) {
255
                foreach ($this->access_list[$resource] as $i => $access) {
256
                    if ($access == $access_list) {
257
                        unset($this->access_list[$resource][$i]);
258
                    }
259
                }
260
            }
261
        }
262
        $this->rebuild_access_list();
263
    }
264
265
    /**
266
     * Agrega un acceso de la lista de resources a un rol
267
     *
268
     * Utilizar '*' como comodín
269
     *
270
     * Ej:
271
     * <code>
272
     * //Acceso para invitados a consultar en clientes
273
     * $acl->allow('invitados', 'clientes', 'consulta');
274
     *
275
     * //Acceso para invitados a consultar e insertar en clientes
276
     * $acl->allow('invitados', 'clientes', array('consulta', 'insertar'));
277
     *
278
     * //Acceso para cualquiera a visualizar en productos
279
     * $acl->allow('*', 'productos', 'visualiza');
280
     *
281
     * //Acceso para cualquiera a visualizar en cualquier resource
282
     * $acl->allow('*', '*', 'visualiza');
283
     * </code>
284
     *
285
     * @param string $role
286
     * @param string $resource
287
     * @param mixed $access
288
     */
289
    public function allow($role, $resource, $access) {
290
        if (!in_array($role, $this->roles_names)) {
291
            throw new KumbiaException("No existe el rol '$role' en la lista");
292
293
        }
294
        if (!in_array($resource, $this->resources_names)) {
295
            throw new KumbiaException("No existe el resource '$resource' en la lista");
296
297
        }
298
        if (is_array($access)) {
299
            foreach ($access as $acc) {
300
                if (!in_array($acc, $this->access_list[$resource])) {
301
                    throw new KumbiaException("No existe el acceso '$acc' en el resource '$resource' de la lista");
302
303
                }
304
            }
305
            foreach ($access as $acc) {
306
                $this->access[$role][$resource][$acc] = 'A';
307
            }
308
        } else {
309
            if (!in_array($access, $this->access_list[$resource])) {
310
                throw new KumbiaException("No existe el acceso '$access' en el resource '$resource' de la lista");
311
312
            }
313
            $this->access[$role][$resource][$access] = 'A';
314
            $this->rebuild_access_list();
315
        }
316
    }
317
318
    /**
319
     * Denegar un acceso de la lista de resources a un rol
320
     *
321
     * Utilizar '*' como comodín
322
     *
323
     * Ej:
324
     * <code>
325
     * //Denega acceso para invitados a consultar en clientes
326
     * $acl->deny('invitados', 'clientes', 'consulta');
327
     *
328
     * //Denega acceso para invitados a consultar e insertar en clientes
329
     * $acl->deny('invitados', 'clientes', array('consulta', 'insertar'));
330
     *
331
     * //Denega acceso para cualquiera a visualizar en productos
332
     * $acl->deny('*', 'productos', 'visualiza');
333
     *
334
     * //Denega acceso para cualquiera a visualizar en cualquier resource
335
     * $acl->deny('*', '*', 'visualiza');
336
     * </code>
337
     *
338
     * @param string $role
339
     * @param string $resource
340
     * @param mixed $access
341
     */
342
    public function deny($role, $resource, $access) {
343
        if (!in_array($role, $this->roles_names)) {
344
            throw new KumbiaException("No existe el rol '$role' en la lista");
345
346
        }
347
        if (!in_array($resource, $this->resources_names)) {
348
            throw new KumbiaException("No existe el resource '$resource' en la lista");
349
350
        }
351
        if (is_array($access)) {
352
            foreach ($access as $acc) {
353
                if (!in_array($acc, $this->access_list[$resource])) {
354
                    throw new KumbiaException("No existe el acceso '$acc' en el resource '$resource' de la lista");
355
356
                }
357
            }
358
            foreach ($access as $acc) {
359
                $this->access[$role][$resource][$acc] = 'D';
360
            }
361
        } else {
362
            if (!in_array($access, $this->access_list[$resource])) {
363
                throw new KumbiaException("No existe el acceso '$access' en el resource '$resource' de la lista");
364
365
            }
366
            $this->access[$role][$resource][$access] = 'D';
367
            $this->rebuild_access_list();
368
        }
369
    }
370
371
    /**
372
     * Devuelve true si un $role, tiene acceso en un resource
373
     *
374
     * <code>
375
     * //Andres tiene acceso a insertar en el resource productos
376
     * $acl->is_allowed('andres', 'productos', 'insertar');
377
     *
378
     * //Invitado tiene acceso a editar en cualquier resource?
379
     * $acl->is_allowed('invitado', '*', 'editar');
380
     *
381
     * //Invitado tiene acceso a editar en cualquier resource?
382
     * $acl->is_allowed('invitado', '*', 'editar');
383
     * </code>
384
     *
385
     * @param string $role
386
     * @param string $resource
387
     * @param mixed $access_list
388
     * @return boolean|null
389
     */
390
    public function is_allowed($role, $resource, $access_list) {
391
        if (!in_array($role, $this->roles_names)) {
392
            throw new KumbiaException("El rol '$role' no existe en la lista en acl::is_allowed");
393
394
        }
395
        if (!in_array($resource, $this->resources_names)) {
396
            throw new KumbiaException("El resource '$resource' no existe en la lista en acl::is_allowed");
397
398
        }
399
        if (is_array($access_list)) {
400
            foreach ($access_list as $access) {
401
                if (!in_array($access, $this->access_list[$resource])) {
402
                    throw new KumbiaException("No existe en acceso '$access' en el resource '$resource' en acl::is_allowed");
403
404
                }
405
            }
406
        } else {
407
            if (!in_array($access_list, $this->access_list[$resource])) {
408
                throw new KumbiaException("No existe en acceso '$access_list' en el resource '$resource' en acl::is_allowed");
409
410
            }
411
        }
412
413
        /* foreach($this->access[$role] as ){
414
415
        } */
416
        // FIXME: Por lo pronto hacemos esta validación, luego se mejorará
417
        if (!isset($this->access[$role][$resource][$access_list])) {
418
            return false;
419
        }
420
421
        if ($this->access[$role][$resource][$access_list] == "A") {
422
            return true;
423
        }
424
    }
425
426
    /**
427
     * Reconstruye la lista de accesos a partir de las herencias
428
     * y accesos permitidos y denegados
429
     *
430
     * @access private
431
     */
432
    private function rebuild_access_list() {
433
        for ($i = 0; $i <= ceil(count($this->roles)*count($this->roles)/2); $i++) {
434
            foreach ($this->roles_names as $role) {
435
                if (isset($this->role_inherits[$role])) {
436
                    foreach ($this->role_inherits[$role] as $role_inherit) {
437
                        if (isset($this->access[$role_inherit])) {
438
                            foreach ($this->access[$role_inherit] as $resource_name => $access) {
439
                                foreach ($access as $access_name                       => $value) {
440
                                    if (!in_array($access_name, $this->access_list[$resource_name])) {
441
                                        unset($this->access[$role_inherit][$resource_name][$access_name]);
442
                                    } else {
443
                                        if (!isset($this->access[$role][$resource_name][$access_name])) {
444
                                            $this->access[$role][$resource_name][$access_name] = $value;
445
                                        }
446
                                    }
447
                                }
448
                            }
449
                        }
450
                    }
451
                }
452
            }
453
        }
454
    }
455
456
}
457