HybridLoginLimitPlugin::login()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 14
ccs 9
cts 9
cp 1
rs 10
cc 4
nc 4
nop 2
crap 4
1
<?php
2
3
namespace Vectorface\Auth\Plugin\Limit;
4
5
use InvalidArgumentException;
6
use Vectorface\Auth\Auth;
7
use Vectorface\Auth\Plugin\BaseAuthPlugin;
8
9
/**
10
 * Limit the number of logins allowed per browser. This is to be used alongside the MemcacheLoginLimitPlugin.
11
 *
12
 * This is not intended to be a security measure, but more as a guard against a single person locking out an entire office that's behind one NAT.
13
 */
14
class HybridLoginLimitPlugin extends BaseAuthPlugin implements LoginLimitPluginInterface
15
{
16
    /**
17
     * The login limit plugins to "combine".
18
     *
19
     * @var LoginLimitPluginInterface[]
20
     */
21
    protected $limiters = [];
22
23
    /**
24
     * Create a new hybrid login limiter.
25
     *
26
     * @param LoginLimitPluginInterface[] $limiters The login limit plugins to combine into one.
27
     */
28 3
    public function __construct(array $limiters = [])
29
    {
30 3
        foreach ($limiters as $limiter) {
31 3
            if (!($limiter instanceof LoginLimitPluginInterface)) {
32 1
                throw new InvalidArgumentException("LoginLimitPluginInterface expected");
33
            }
34 2
            $this->limiters[] = $limiter;
35
        }
36 2
    }
37
38
    /**
39
     * Decrement the number of attempts.
40
     *
41
     * This is intended for application logic when a login attempt can be forgiven.
42
     */
43 1
    public function decrementAttempts()
44
    {
45 1
        foreach ($this->limiters as $limiter) {
46 1
            $limiter->decrementAttempts();
47
        }
48 1
    }
49
50
    /**
51
     * Get the number of login attempts performed so far.
52
     *
53
     * Note: The number of attempts does not necessarily imply success or
54
     * failure, though if a logged-in user has 3 login attempts, that usually
55
     * means 2 failed 1 successful. If the user has not authenticated, 3
56
     * attempts means 3 failed attempts.
57
     *
58
     * @return int The number of login attempts for this user.
59
     */
60 1
    public function getLoginAttempts()
61
    {
62 1
        $attempts = 0;
63 1
        foreach ($this->limiters as $limiter) {
64 1
            $attempts = max($limiter->getLoginAttempts(), $attempts);
65
        }
66 1
        return $attempts;
67
    }
68
69
    /**
70
     * Get the maximum number of allowed login attempts.
71
     *
72
     * Note: max attempts for a given IP isn't published.
73
     *
74
     * @return int
75
     */
76 1
    public function getMaxLoginAttempts()
77
    {
78 1
        $attempts = PHP_INT_MAX;
79 1
        foreach ($this->limiters as $limiter) {
80 1
            $attempts = min($limiter->getMaxLoginAttempts(), $attempts);
81
        }
82 1
        return $attempts;
83
    }
84
85
    /**
86
     * Auth plugin hook to be fired on login.
87
     *
88
     * @param string $username
89
     * @param string $password
90
     * @return int
91
     */
92 2
    public function login($username, $password)
93
    {
94 2
        $result = Auth::RESULT_NOOP;
95 2
        foreach ($this->limiters as $limiter) {
96 2
            $limiterResult = $limiter->login($username, $password);
0 ignored issues
show
Bug introduced by
The method login() does not exist on Vectorface\Auth\Plugin\L...ginLimitPluginInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Vectorface\Auth\Plugin\L...ginLimitPluginInterface. ( Ignorable by Annotation )

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

96
            /** @scrutinizer ignore-call */ 
97
            $limiterResult = $limiter->login($username, $password);
Loading history...
97
98 2
            if (in_array($limiterResult, [Auth::RESULT_FAILURE, Auth::RESULT_FORCE])) {
99 1
                return $limiterResult;
100 2
            } elseif ($limiterResult === Auth::RESULT_SUCCESS) {
101 1
                $result = $limiterResult;
102
            }
103
        }
104
105 2
        return $result;
106
    }
107
}
108