Completed
Push — master ( f22a46...046041 )
by Patrick
02:27 queued 12s
created

AuthProvider::deletePendingUsersByFilter()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
namespace Flipside;
3
/**
4
 * AuthProvider class
5
 *
6
 * This file describes the AuthProvider Singleton
7
 *
8
 * PHP version 5 and 7
9
 *
10
 * @author Patrick Boyd / [email protected]
11
 * @copyright Copyright (c) 2015, Austin Artistic Reconstruction
12
 * @license http://www.apache.org/licenses/ Apache 2.0 License
13
 */
14
15
/**
16
 * Allow other classes to be loaded as needed
17
 */
18
require_once('Autoload.php');
19
20
/**
21
 * A Singleton class to abstract access to the authentication providers.
22
 *
23
 * This class is the primary method to access user data, login, and other authenication information.
24
 */
25
class AuthProvider extends Provider
26
{
27
    /**
28
     * Load the authentrication providers specified in the Settings $authProviders array
29
     *
30
     * @SuppressWarnings("StaticAccess")
31
     */
32
    protected function __construct()
33
    {
34
        $settings = Settings::getInstance();
35
        $this->methods = $settings->getClassesByPropName('authProviders');
36
    }
37
38
    /**
39
     * Get the Auth\User class instance for the specified login
40
     *
41
     * Unlike the AuthProvider::login() function. This function will not impact the SESSION
42
     *
43
     * @param string $username The username of the User
44
     * @param string $password The password of the User
45
     *
46
     * @return Auth\User|false The User with the specified credentials or false if the credentials are not valid
47
     */
48
    public function getUserByLogin($username, $password)
49
    {
50
        $res = false;
51
        $count = count($this->methods);
52
        for($i = 0; $i < $count; $i++)
53
        {
54
            $res = $this->methods[$i]->login($username, $password);
55
            if($res !== false)
56
            {
57
                return $this->methods[$i]->getUser($res);
58
            }
59
        }
60
        return $res;
61
    }
62
63
    /**
64
     * Use the provided credetials to log the user on
65
     *
66
     * @param string $username The username of the User
67
     * @param string $password The password of the User
68
     *
69
     * @return true|false true if the login was successful, false otherwise
70
     */
71
    public function login($username, $password)
72
    {
73
        $res = false;
74
        $count = count($this->methods);
75
        for($i = 0; $i < $count; $i++)
76
        {
77
            $res = $this->methods[$i]->login($username, $password);
78
            if($res !== false)
79
            {
80
                if(isset($res['extended']) && isset($res['extended']['jpegphoto']))
81
                {
82
                    $res['extended']['jpegphoto']=true;
83
                }
84
                FlipSession::setVar('AuthMethod', get_class($this->methods[$i]));
85
                FlipSession::setVar('AuthData', $res);
86
                break;
87
            }
88
        }
89
        return $res;
90
    }
91
92
    /**
93
     * Determine if the user is still logged on from the session data
94
     *
95
     * @param stdClass $data The AuthData from the session
96
     * @param string $methodName The AuthMethod from the session
97
     *
98
     * @return true|false true if user is logged on, false otherwise
99
     */
100
    public function isLoggedIn($data, $methodName)
101
    {
102
        $auth = $this->getMethodByName($methodName);
103
        return $auth->isLoggedIn($data);
104
    }
105
106
    /**
107
     * Obtain the currently logged in user from the session data
108
     *
109
     * @param stdClass $data The AuthData from the session
110
     * @param string $methodName The AuthMethod from the session
111
     *
112
     * @return Auth\User|false The User instance if user is logged on, false otherwise
113
     */
114
    public function getUser($data, $methodName)
115
    {
116
        $auth = $this->getMethodByName($methodName);
117
        return $auth->getUser($data);
118
    }
119
120
    /**
121
     * Merge or set the returnValue as appropriate
122
     *
123
     * @param false|Auth\Group|Auth\User $returnValue The value to merge to
124
     * @param Auth\Group|Auth\User $res The value to merge from
125
     *
126
     * @return Auth\Group|false The merged returnValue
127
     */
128
    public function mergeResult(&$returnValue, $res)
129
    {
130
        if($res === false)
131
        {
132
            return;
133
        }
134
        if($returnValue === false)
135
        {
136
            $returnValue = $res;
137
            return;
138
        }
139
        $returnValue->merge($res);
140
    }
141
142
    /**
143
     * Get an Auth\Group by its name
144
     *
145
     * @param string $name The name of the group
146
     * @param string $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
147
     *
148
     * @return Auth\Group|false The Group instance if a group with that name exists, false otherwise
149
     */
150 View Code Duplication
    public function getGroupByName($name, $methodName = false)
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...
151
    {
152
        if($methodName === false)
153
        {
154
            return $this->callOnEach('getGroupByName', array($name));
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callOnEach('getGr...ByName', array($name)); of type Flipside\Auth\Group|Flipside\Auth\User|false adds the type Flipside\Auth\User to the return on line 154 which is incompatible with the return type documented by Flipside\AuthProvider::getGroupByName of type Flipside\Auth\Group|false.
Loading history...
155
        }
156
        $auth = $this->getMethodByName($methodName);
157
        return $auth->getGroupByName($name);
158
    }
159
160
    /**
161
     * Get an array of Auth\User from a filtered set
162
     *
163
     * @param Data\Filter|boolean $filter The filter conditions or false to retreive all
164
     * @param array|boolean $select The user fields to obtain or false to obtain all
165
     * @param integer|boolean $top The number of users to obtain or false to obtain all
166
     * @param integer|boolean $skip The number of users to skip or false to skip none
167
     * @param array|boolean $orderby The field to sort by and the method to sort or false to not sort
168
     * @param string|boolean $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
169
     *
170
     * @return array|boolean An array of Auth\User objects or false if no users were found
171
     */
172
    public function getUsersByFilter($filter, $select = false, $top = false, $skip = false, $orderby = false, $methodName = false)
173
    {
174
        return $this->callFunction($methodName, 'getUsersByFilter', array($filter, $select, $top, $skip, $orderby), 
175
                                    'current', false, array($this, 'mergeResult'));
176
    }
177
178
    /**
179
     * Get an array of Auth\PendingUser from a filtered set
180
     *
181
     * @param Data\Filter|boolean $filter The filter conditions or false to retreive all
182
     * @param array|boolean $select The user fields to obtain or false to obtain all
183
     * @param integer|boolean $top The number of users to obtain or false to obtain all
184
     * @param integer|boolean $skip The number of users to skip or false to skip none
185
     * @param array|boolean $orderby The field to sort by and the method to sort or false to not sort
186
     * @param string|boolean $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
187
     *
188
     * @return array|boolean An array of Auth\PendingUser objects or false if no pending users were found
189
     */
190
    public function getPendingUsersByFilter($filter, $select = false, $top = false, $skip = false, $orderby = false, $methodName = false)
191
    {
192
        return $this->callFunction($methodName, 'getPendingUsersByFilter', array($filter, $select, $top, $skip, $orderby),
193
                                    'pending', false, array($this, 'mergeResult'));
194
    }
195
196
    /**
197
     * Get an array of Auth\Group from a filtered set
198
     *
199
     * @param Data\Filter|false $filter The filter conditions or false to retreive all
200
     * @param array|false $select The group fields to obtain or false to obtain all
201
     * @param integer|false $top The number of groups to obtain or false to obtain all
202
     * @param integer|false $skip The number of groups to skip or false to skip none
203
     * @param array|false $orderby The field to sort by and the method to sort or false to not sort
204
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
205
     *
206
     * @return array|false An array of Auth\Group objects or false if no pending users were found
207
     */
208
    public function getGroupsByFilter($filter, $select = false, $top = false, $skip = false, $orderby = false, $methodName = false)
209
    {
210
        return $this->callFunction($methodName, 'getGroupsByFilter', array($filter, $select, $top, $skip, $orderby),
211
                                    'current', false, array($this, 'mergeResult'));
212
    }
213
214
    /**
215
     * Get the number of currently active users on the system
216
     *
217
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
218
     *
219
     * @return integer The number of currently active users on the system
220
     */
221
    public function getActiveUserCount($methodName = false)
222
    {
223
        if($methodName === false)
224
        {
225
            return $this->addFromEach('getActiveUserCount', 'current');
226
        }
227
        $auth = $this->getMethodByName($methodName);
228
        return $auth->getActiveUserCount();
229
    }
230
231
    /**
232
     * Get the number of currently pending users on the system
233
     *
234
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
235
     *
236
     * @return integer The number of currently pending users on the system
237
     */
238
    public function getPendingUserCount($methodName = false)
239
    {
240
        if($methodName === false)
241
        {
242
            return $this->addFromEach('getPendingUserCount', 'pending');
243
        }
244
        $auth = $this->getMethodByName($methodName);
245
        return $auth->getPendingUserCount();
246
    }
247
248
    /**
249
     * Get the number of current groups on the system
250
     *
251
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
252
     *
253
     * @return integer The number of current groups on the system
254
     */
255
    public function getGroupCount($methodName = false)
256
    {
257
        if($methodName === false)
258
        {
259
            return $this->addFromEach('getGroupCount', 'current');
260
        }
261
        $auth = $this->getMethodByName($methodName);
262
        return $auth->getGroupCount();
263
    }
264
265
    /**
266
     * Get the login links for all supplementary Authenitcation mechanisms
267
     *
268
     * This will return an array of links to any supplementary authentication mechanims. For example, Goodle is 
269
     * a supplementary authentication mechanism.
270
     *
271
     * @return array An array of suppmentary authentication mechanism links
272
     */
273
    public function getSupplementaryLinks()
274
    {
275
        $ret = array();
276
        $count = count($this->methods);
277 View Code Duplication
        for($i = 0; $i < $count; $i++)
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...
278
        {
279
            if($this->methods[$i]->supplement === false)
280
            {
281
                continue;
282
            }
283
284
            array_push($ret, $this->methods[$i]->getSupplementLink());
285
        }
286
        return $ret;
287
    }
288
289
    /**
290
     * Impersonate the user specified
291
     *
292
     * This will replace the user in the session with the specified user. In order
293
     * to undo this operation a user must logout.
294
     *
295
     * @param array|Auth\User $userArray Data representing the user
296
     */
297
    public function impersonateUser($userArray)
298
    {
299
        if(!is_object($userArray))
300
        {
301
            $userArray = new $userArray['class']($userArray);
302
        }
303
        \FlipSession::setUser($userArray);
304
    }
305
306
    /**
307
     * Get the pending user reresented by the supplied hash
308
     *
309
     * @param string $hash The hash value representing the Penging User
310
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
311
     *
312
     * @return Auth\PendingUser|false The Auth\PendingUser instance or false if no user is matched by the provided hash
313
     */
314 View Code Duplication
    public function getTempUserByHash($hash, $methodName = false)
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...
315
    {
316
        if($methodName === false)
317
        {
318
            return $this->callOnEach('getTempUserByHash', array($hash), 'pending');
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callOnEach('getTe...ray($hash), 'pending'); of type Flipside\Auth\Group|Flipside\Auth\User|false adds the type Flipside\Auth\Group to the return on line 318 which is incompatible with the return type documented by Flipside\AuthProvider::getTempUserByHash of type Flipside\Auth\PendingUser|false.
Loading history...
319
        }
320
        $auth = $this->getMethodByName($methodName);
321
        return $auth->getTempUserByHash($hash);
322
    }
323
324
    /**
325
     * Create a pending user
326
     *
327
     * @param array $user An array of information about the user to create
328
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
329
     *
330
     * @return boolean true if the user was successfully created. Otherwise false.
331
     */
332 View Code Duplication
    public function createPendingUser($user, $methodName = false)
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...
333
    {
334
        if($methodName === false)
335
        {
336
            $count = count($this->methods);
337
            for($i = 0; $i < $count; $i++)
338
            {
339
                if($this->methods[$i]->pending === false)
340
                {
341
                    continue;
342
                }
343
344
                $ret = $this->methods[$i]->createPendingUser($user);
345
                if($ret !== false)
346
                {
347
                    return true;
348
                }
349
            }
350
            return false;
351
        }
352
        $auth = $this->getMethodByName($methodName);
353
        return $auth->createPendingUser($user);
354
    }
355
356
    /**
357
     * Convert a Auth\PendingUser into an Auth\User
358
     *
359
     * This will allow a previously pending user the ability to log on in the future as an active user. It will also
360
     * have the side effect of logging the user on now.
361
     *
362
     * @param Auth\PendingUser $user The user to turn into a current user
363
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
364
     *
365
     * @return boolean true if the user was successfully created. Otherwise false.
366
     */
367 View Code Duplication
    public function activatePendingUser($user, $methodName = false)
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...
368
    {
369
        if($methodName === false)
370
        {
371
            $count = count($this->methods);
372
            for($i = 0; $i < $count; $i++)
373
            {
374
                if($this->methods[$i]->current === false)
375
                {
376
                    continue;
377
                }
378
379
                $ret = $this->methods[$i]->activatePendingUser($user);
380
                if($ret !== false)
381
                {
382
                    $this->impersonateUser($ret);
383
                    return true;
384
                }
385
            }
386
            return false;
387
        }
388
        $auth = $this->getMethodByName($methodName);
389
        return $auth->activatePendingUser($user);
390
    }
391
392
    /**
393
     * Get a current user by a password reset hash
394
     *
395
     * @param string $hash The current password reset hash for the user
396
     * @param string|false $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
397
     *
398
     * @return Auth\User|false The user if the password reset hash is valid. Otherwise false.
399
     */
400
    public function getUserByResetHash($hash, $methodName = false)
401
    {
402
        if($methodName === false)
403
        {
404
            return $this->callOnEach('getUserByResetHash', array($hash), 'current');
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callOnEach('getUs...ray($hash), 'current'); of type Flipside\Auth\Group|Flipside\Auth\User|false adds the type Flipside\Auth\Group to the return on line 404 which is incompatible with the return type documented by Flipside\AuthProvider::getUserByResetHash of type Flipside\Auth\User|false.
Loading history...
405
        }
406
        $auth = $this->getMethodByName($methodName);
407
        if($auth === false)
408
        {
409
            return $this->getUserByResetHash($hash, false);
410
        }
411
        return $auth->getUserByResetHash($hash);
412
    }
413
414
    /**
415
     * Get the Auth\Authenticator by host name
416
     *
417
     * @param string $host The host name used by the supplemental authentication mechanism
418
     *
419
     * @return Auth\Authenticator|false The Authenticator if the host is supported by a loaded Authenticator. Otherwise false.
420
     */
421
    public function getSuplementalProviderByHost($host)
422
    {
423
        $count = count($this->methods);
424 View Code Duplication
        for($i = 0; $i < $count; $i++)
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...
425
        {
426
            if($this->methods[$i]->supplement === false)
427
            {
428
                continue;
429
            }
430
431
            if($this->methods[$i]->getHostName() === $host)
432
            {
433
                return $this->methods[$i];
434
            }
435
        }
436
        return false;
437
    }
438
439
    /**
440
     * Delete any pending users that match the filter
441
     *
442
     * @param \Data\Filter|boolean $filter The filter to delete with or false to delete all
443
     * @param string|boolean $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
444
     *
445
     * @return boolean True if the users were deleted, false otherwise
446
     */
447
    public function deletePendingUsersByFilter($filter, $methodName = false)
448
    {
449
        $users = $this->getPendingUsersByFilter($filter, false, false, false, false, $methodName);
450
        if($users === false)
451
        {
452
            return false;
453
        }
454
        $count = count($users);
455
        for($i = 0; $i < $count; $i++)
456
        {
457
            $users[$i]->delete();
458
        }
459
        return true;
460
    }
461
462
    /**
463
     * Get the user by the one time access code
464
     *
465
     * @param string $key The user's access code
466
     * @param string|boolean $methodName The AuthMethod if information is desired only from a particular Auth\Authenticator
467
     *
468
     * @return boolean|\Auth\User The User specified by the access code or false otherwise
469
     */
470 View Code Duplication
    public function getUserByAccessCode($key, $methodName = false)
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...
471
    {
472
        if($methodName === false)
473
        {
474
            return $this->callOnEach('getUserByAccessCode', array($key), 'current');
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->callOnEach...rray($key), 'current'); (Flipside\Auth\Group|Flipside\Auth\User|false) is incompatible with the return type documented by Flipside\AuthProvider::getUserByAccessCode of type boolean|Auth\User.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
475
        }
476
        $auth = $this->getMethodByName($methodName);
0 ignored issues
show
Bug introduced by
It seems like $methodName defined by parameter $methodName on line 470 can also be of type boolean; however, Flipside\Provider::getMethodByName() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
477
        return $auth->getUserByAccessCode($key);
478
    }
479
}
480
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
481