CookieLoginLimitPlugin   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 9
eloc 23
c 1
b 0
f 0
dl 0
loc 122
ccs 24
cts 24
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A login() 0 9 2
A setLoginAttempts() 0 8 2
A getLoginAttempts() 0 6 2
A getMaxLoginAttempts() 0 3 1
A __construct() 0 4 1
A decrementAttempts() 0 3 1
1
<?php
2
3
namespace Vectorface\Auth\Plugin\Limit;
4
5
use Vectorface\Auth\Auth;
6
use Vectorface\Auth\Plugin\BaseAuthPlugin;
7
8
/**
9
 * Limit the number of logins allowed per browser. This is to be used alongside the MemcacheLoginLimitPlugin.
10
 *
11
 * 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.
12
 */
13
class CookieLoginLimitPlugin extends BaseAuthPlugin implements LoginLimitPluginInterface
14
{
15
    /**
16
     * Name of the cookie.
17
     */
18
    const COOKIE_NAME = "AuthCLLP";
19
20
    /**
21
     * Default maximum number of login attempts.
22
     */
23
    const MAX_ATTEMPTS = 3;
24
25
    /**
26
     * Default timeout in seconds.
27
     */
28
    const TIMEOUT = 900;
29
30
    /**
31
     * The maximum allowed number of login attempts within the timeout.
32
     *
33
     * @var int
34
     */
35
    protected $maxAttempts;
36
37
    /**
38
     * The amount of time that must pass after the maximum number of failed login attempts.
39
     *
40
     * @var int
41
     */
42
    protected $timeout;
43
44
    /**
45
     * The number of attempts so far.
46
     *
47
     * @var int
48
     */
49
    protected $attempts;
50
51
    /**
52
     * Create a new cookie-based login limiter.
53
     *
54
     * @param int $attempts The maximum number of login attempts to be allowed.
55
     * @param int $sec The amount of time (in seconds) to block login attempts after max attempts has been surpassed.
56
     */
57 3
    public function __construct($attempts = self::MAX_ATTEMPTS, $sec = self::TIMEOUT)
58
    {
59 3
        $this->maxAttempts = (int)$attempts;
60 3
        $this->timeout = (int)$sec;
61 3
    }
62
63
    /**
64
     * Decrement the number of attempts.
65
     *
66
     * This is intended for application logic when a login attempt can be forgiven.
67
     */
68 2
    public function decrementAttempts()
69
    {
70 2
        $this->setLoginAttempts(-1);
71 2
    }
72
73
    /**
74
     * Get the number of login attempts performed so far.
75
     *
76
     * Note: The number of attempts does not necessarily imply success or
77
     * failure, though if a logged-in user has 3 login attempts, that usually
78
     * means 2 failed 1 successful. If the user has not authenticated, 3
79
     * attempts means 3 failed attempts.
80
     *
81
     * @return int The number of login attempts for this user.
82
     */
83 2
    public function getLoginAttempts()
84
    {
85 2
        if (!isset($this->attempts)) {
86 2
            $this->attempts = $_COOKIE[self::COOKIE_NAME] ?? 0;
87
        }
88 2
        return $this->attempts;
89
    }
90
91
    /**
92
     * Get the maximum number of allowed login attempts.
93
     *
94
     * Note: max attempts for a given IP isn't published.
95
     *
96
     * @return int
97
     */
98 2
    public function getMaxLoginAttempts()
99
    {
100 2
        return $this->maxAttempts;
101
    }
102
103
    /**
104
     * Used internally to set the number of login attempts
105
     *
106
     * @param int $diff The change to number of login attempts, usually positive or negative 1.
107
     * @return int The number of attempts for the given username and IP address.
108
     */
109 2
    protected function setLoginAttempts($diff)
110
    {
111 2
        $this->attempts = $this->getLoginAttempts() + $diff;
112 2
        $_COOKIE[self::COOKIE_NAME] = $this->attempts;
113 2
        if (!headers_sent()) {
114 2
            setcookie(self::COOKIE_NAME, $this->attempts, time() + $this->timeout);
115
        }
116 2
        return $this->attempts;
117
    }
118
119
    /**
120
     * Auth plugin hook to be fired on login.
121
     *
122
     * @param string $username
123
     * @param string $password
124
     * @return int
125
     */
126 2
    public function login($username, $password)
127
    {
128 2
        $attempts = $this->setLoginAttempts(1);
129
130 2
        if ($attempts > $this->maxAttempts) {
131 2
            return Auth::RESULT_FAILURE;
132
        }
133
134 2
        return Auth::RESULT_NOOP;
135
    }
136
}
137