Completed
Push — master ( 579af5...b29473 )
by Oleg
07:53
created

AccessFilter::checkRule()   B

Complexity

Conditions 6
Paths 2

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 14
rs 8.8571
cc 6
eloc 10
nc 2
nop 1
1
<?php /** AccessFilterMicro */
2
3
namespace Micro\Filter;
4
5
/**
6
 * Class AccessFilter
7
 *
8
 * @author Oleg Lunegov <[email protected]>
9
 * @link https://github.com/lugnsk/micro
10
 * @copyright Copyright &copy; 2013 Oleg Lunegov
11
 * @license /LICENSE
12
 * @package Micro
13
 * @subpackage Filter
14
 * @version 1.0
15
 * @since 1.0
16
 */
17
class AccessFilter extends Filter
18
{
19
    /**
20
     * @inheritdoc
21
     */
22
    public function pre(array $params)
23
    {
24
        foreach ($params['rules'] AS $rule) {
25
            $res = $this->checkRule($rule);
26
27
            if ($res === true) {
28
                return true;
29 View Code Duplication
            } elseif ($res === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
30
                $this->result = [
31
                    'redirect' => !empty($rule['redirect']) ? $rule['redirect'] : null,
32
                    'message' => !empty($rule['message']) ? $rule['message'] : 'Access denied!'
33
                ];
34
35
                return false;
36
            } elseif ($res === null) {
37
                continue;
38
            }
39
        }
40
41
        return true;
42
    }
43
44
    /**
45
     * Check one rule
46
     *
47
     * @access protected
48
     *
49
     * @param array $rule rule definition
50
     *
51
     * @return bool|null
52
     */
53
    protected function checkRule(array $rule)
54
    {
55
        if (
56
            $this->matchAction($rule)
57
            && $this->matchUser($rule)
58
            && $this->matchRole($rule)
59
            && $this->matchIP($rule)
60
            && $this->matchVerb($rule)
61
        ) {
62
            return $rule['allow'];
63
        } else {
64
            return null;
65
        }
66
    }
67
68
    /**
69
     * Match action
70
     *
71
     * @access protected
72
     *
73
     * @param array $rule rule definition
74
     *
75
     * @return bool
76
     */
77
    protected function matchAction($rule)
78
    {
79
        if (empty($rule['actions'])) {
80
            return true;
81
        }
82
83
        if (is_array($rule['actions'])) {
84
            return in_array($this->action, $rule['actions'], true);
85
        }
86
87
        return $this->action === $rule['actions'];
88
    }
89
90
    /**
91
     * Match user
92
     *
93
     * @access protected
94
     * @global Container
95
     *
96
     * @param array $rule rule definition
97
     *
98
     * @return bool
99
     */
100
    protected function matchUser($rule)
101
    {
102
        if (empty($rule['users'])) {
103
            return true;
104
        }
105
106
        if (!is_array($rule['users'])) {
107
            $rule['users'][] = $rule['users'];
108
        }
109
110
        foreach ($rule['users'] AS $u) {
111
            switch ($u) {
112
                case '*':
113
                    return true;
114
115
                case '?':
116
                    if ($this->container->user->isGuest()) {
0 ignored issues
show
Bug introduced by
Accessing user on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
117
                        return true;
118
                    }
119
                    break;
120
121
                case '@':
122
                    if (!$this->container->user->isGuest()) {
0 ignored issues
show
Bug introduced by
Accessing user on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
123
                        return true;
124
                    }
125
                    break;
126
127
                default:
128
                    if ($this->container->user->getID() === $u) {
0 ignored issues
show
Bug introduced by
Accessing user on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
129
                        return true;
130
                    }
131
            }
132
        }
133
134
        return false;
135
    }
136
137
    /**
138
     * Match role
139
     *
140
     * @access protected
141
     * @global Container
142
     *
143
     * @param array $rule rule definition
144
     *
145
     * @return bool
146
     */
147 View Code Duplication
    protected function matchRole($rule)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
    {
149
        if (empty($rule['roles'])) {
150
            return true;
151
        }
152
153
        if (!is_array($rule['roles'])) {
154
            $rule['roles'][] = $rule['roles'];
155
        }
156
157
        foreach ($rule['roles'] AS $role) {
158
            if ($this->container->user->check($role)) {
0 ignored issues
show
Bug introduced by
Accessing user on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
159
                return true;
160
            }
161
        }
162
163
        return false;
164
    }
165
166
    /**
167
     * Match IP
168
     *
169
     * @access protected
170
     * @global Container
171
     *
172
     * @param array $rule rule definition
173
     *
174
     * @return bool
175
     */
176
    protected function matchIP($rule)
177
    {
178
        if (empty($rule['ips'])) {
179
            return true;
180
        }
181
182
        if (!is_array($rule['ips'])) {
183
            $rule['ips'][] = $rule['ips'];
184
        }
185
186
        $userIp = $this->container->request->getUserIP();
0 ignored issues
show
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
187
188
        foreach ($rule['ips'] AS $r) {
189
            if ($r === '*' || $r === $userIp || (($pos = strpos($r, '*')) !== false && !strncmp($userIp, $r, $pos))) {
190
                return true;
191
            }
192
        }
193
194
        return false;
195
    }
196
197
    /**
198
     * Match verbose
199
     *
200
     * @access protected
201
     * @global Container
202
     *
203
     * @param array $rule rule definition
204
     *
205
     * @return bool
206
     */
207 View Code Duplication
    protected function matchVerb($rule)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
208
    {
209
        if (empty($rule['verb'])) {
210
            return true;
211
        }
212
213
        if (!is_array($rule['verb'])) {
214
            $rule['verb'][] = $rule['verb'];
215
        }
216
217
        $verb = $this->container->request->getMethod();
0 ignored issues
show
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
218
219
        foreach ($rule['verb'] AS $v) {
220
            if ($v === $verb) {
221
                return true;
222
            }
223
        }
224
225
        return false;
226
    }
227
228
    /**
229
     * @inheritdoc
230
     */
231
    public function post(array $params)
232
    {
233
        return $params['data'];
234
    }
235
}
236