EnhancedAuthentication::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 23
ccs 15
cts 15
cp 1
rs 9.7998
c 0
b 0
f 0
cc 1
nc 1
nop 4
crap 1
1
<?php
2
3
/**
4
 * Linna Framework.
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2018, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types=1);
11
12
namespace Linna\Authentication;
13
14
use Linna\Session\Session;
15
16
/**
17
 * Extend basic user authentication system with more security checks.
18
 */
19
class EnhancedAuthentication extends Authentication
20
{
21
    /**
22
     * @var int Max attempts for user name.
23
     */
24
    protected int $maxAttemptsForUserName = 5;
25
26
    /**
27
     * @var int Max attempts for session id.
28
     */
29
    protected int $maxAttemptsForSessionId = 10;
30
31
    /**
32
     * @var int Max attempts for ip address.
33
     */
34
    protected int $maxAttemptsForIpAddress = 20;
35
36
    /**
37
     * @var int Max attempts for second.
38
     */
39
    protected int $maxAttemptsForSecond = 40;
40
41
    /**
42
     * @var int Ban time in seconds.
43
     */
44
    protected int $banTimeInSeconds = 900;
45
46
    /**
47
     * @var EnhancedAuthenticationMapperInterface Enhanced Authentication Mapper
48
     */
49
    private EnhancedAuthenticationMapperInterface $enhancedAuthenticationMapper;
50
51
    /**
52
     * Class Constructor.
53
     *
54
     * <pre><code class="php">use Linna\Authentication\EnhancedAuthentication;
55
     * use Linna\Authentication\EnhancedAuthenticationMapper;
56
     * use Linna\Authentication\Password;
57
     * use Linna\Session\Session;
58
     * use Linna\Storage\ExtendedPDO;
59
     * use Linna\Storage\StorageFactory;
60
     *
61
     * $session = new Session();
62
     * $password = new Password();
63
     * $pdo = (new StorageFactory('pdo', $options))->get();
64
     * $enhancedAuthenticationMapper = new EnhancedAuthenticationMapper($pdo);
65
     *
66
     * $enhancedAuthentication = new EnhancedAuthentication($session, $password, $enhancedAuthenticationMapper);
67
     * </code></pre>
68
     *
69
     * @param Session                               $session                        Session class instance.
70
     * @param Password                              $password                       Password class instance.
71
     * @param EnhancedAuthenticationMapperInterface $enhancedAuthenticationMapper   Implementation of EnhancedAuthenticationMapper.
72
     * @param array<int>                            $options                        Class options.
73
     */
74 2
    public function __construct(
75
        Session $session,
76
        Password $password,
77
        EnhancedAuthenticationMapperInterface $enhancedAuthenticationMapper,
78
        array $options = []
79
    ) {
80 2
        parent::__construct($session, $password);
81
82 2
        $this->enhancedAuthenticationMapper = $enhancedAuthenticationMapper;
83
84
        [
85 2
            'maxAttemptsForUserName'  => $this->maxAttemptsForUserName,
86 1
            'maxAttemptsForSessionId' => $this->maxAttemptsForSessionId,
87 1
            'maxAttemptsForIpAddress' => $this->maxAttemptsForIpAddress,
88 1
            'maxAttemptsForSecond'    => $this->maxAttemptsForSecond,
89 1
            'banTimeInSeconds'        => $this->banTimeInSeconds
90 2
        ] = \array_replace_recursive([
91 2
            'maxAttemptsForUserName'  => $this->maxAttemptsForUserName,
92 2
            'maxAttemptsForSessionId' => $this->maxAttemptsForSessionId,
93 2
            'maxAttemptsForIpAddress' => $this->maxAttemptsForIpAddress,
94 2
            'maxAttemptsForSecond'    => $this->maxAttemptsForSecond,
95 2
            'banTimeInSeconds'        => $this->banTimeInSeconds
96 2
        ], $options);
97 1
    }
98
99
    /**
100
     * Return how many attemps are left for incorrect password.
101
     *
102
     * <pre><code class="php">$userName = 'root';
103
     * $enhancedAuthentication->getAttemptsLeftWithSameUser($userName);
104
     * </code></pre>
105
     *
106
     * @param string $userName User for which to retrieve login attempts.
107
     *
108
     * @return int Number of attempts with same user.
109
     */
110 28
    public function getAttemptsLeftWithSameUser(string $userName): int
111
    {
112 28
        $attemptsLeft = ((int) $this->maxAttemptsForUserName) - $this->enhancedAuthenticationMapper->fetchAttemptsWithSameUser($userName, $this->banTimeInSeconds);
113
114 28
        return \max(0, $attemptsLeft);
115
    }
116
117
    /**
118
     * Return how many attemps are left for same session id.
119
     *
120
     * <pre><code class="php">$sessionId = '47u2hrm1n79u2ae1992vmhgpat';
121
     * $enhancedAuthentication->getAttemptsLeftWithSameSession($sessionId);
122
     * </code></pre>
123
     *
124
     * @param string $sessionId Session id for which to retrieve login attempts.
125
     *
126
     * @return int Number of attempts with same session.
127
     */
128 28
    public function getAttemptsLeftWithSameSession(string $sessionId): int
129
    {
130 28
        $attemptsLeft = ((int) $this->maxAttemptsForSessionId) - $this->enhancedAuthenticationMapper->fetchAttemptsWithSameSession($sessionId, $this->banTimeInSeconds);
131
132 28
        return \max(0, $attemptsLeft);
133
    }
134
135
    /**
136
     * Return how many attemps are left for same ip.
137
     *
138
     * <pre><code class="php">$ipAddress = '192.168.0.15';
139
     * $enhancedAuthentication->getAttemptsLeftWithSameIp($ipAddress);
140
     * </code></pre>
141
     *
142
     * @param string $ipAddress Ip address for which to retrieve login attempts.
143
     *
144
     * @return int Number of attempts with same ip.
145
     */
146 28
    public function getAttemptsLeftWithSameIp(string $ipAddress): int
147
    {
148 28
        $attemptsLeft = ((int) $this->maxAttemptsForIpAddress) - $this->enhancedAuthenticationMapper->fetchAttemptsWithSameIp($ipAddress, $this->banTimeInSeconds);
149
150 28
        return \max(0, $attemptsLeft);
151
    }
152
153
    /**
154
     * Check if an user is banned from do login.
155
     *
156
     * <pre><code class="php">$userName = 'root';
157
     * $enhancedAuthentication->isUserBanned($userName);
158
     * </code></pre>
159
     *
160
     * @param string $userName User for which check if is banned.
161
     *
162
     * @return bool
163
     */
164 28
    public function isUserBanned(string $userName): bool
165
    {
166 28
        return !$this->getAttemptsLeftWithSameUser($userName);
167
    }
168
169
    /**
170
     * Check if a session id is banned from do login.
171
     *
172
     * <pre><code class="php">$sessionId = '47u2hrm1n79u2ae1992vmhgpat';
173
     * $enhancedAuthentication->isSessionBanned($sessionId);
174
     * </code></pre>
175
     *
176
     * @param string $sessionId Session id for wich check if is banned.
177
     *
178
     * @return bool
179
     */
180 28
    public function isSessionBanned(string $sessionId): bool
181
    {
182 28
        return !$this->getAttemptsLeftWithSameSession($sessionId);
183
    }
184
185
    /**
186
     * Check if an ip address is banned from do login.
187
     *
188
     * <pre><code class="php">$ipAddress = '192.168.0.15';
189
     * $enhancedAuthentication->isIpBanned($ipAddress);
190
     * </code></pre>
191
     *
192
     * @param string $ipAddress Ip address for wich check if is banned.
193
     *
194
     * @return bool
195
     */
196 28
    public function isIpBanned(string $ipAddress): bool
197
    {
198 28
        return !$this->getAttemptsLeftWithSameIp($ipAddress);
199
    }
200
}
201