]>
git.immae.eu Git - github/shaarli/Shaarli.git/blob - application/security/BanManager.php
4 namespace Shaarli\Security
;
6 use Psr\Log\LoggerInterface
;
7 use Shaarli\Helper\FileUtils
;
12 * Failed login attempts will store the associated IP address.
13 * After N failed attempts, the IP will be prevented from log in for duration D.
14 * Both N and D can be set in the configuration file.
16 * @package Shaarli\Security
20 /** @var array List of allowed proxies IP */
21 protected $trustedProxies;
23 /** @var int Number of allowed failed attempt before the ban */
24 protected $nbAttempts;
26 /** @var int Ban duration in seconds */
27 protected $banDuration;
29 /** @var string Path to the file containing IP bans and failures */
32 /** @var LoggerInterface Path to the log file, used to log bans */
35 /** @var array List of IP with their associated number of failed attempts */
36 protected $failures = [];
38 /** @var array List of banned IP with their associated unban timestamp */
42 * BanManager constructor.
44 * @param array $trustedProxies List of allowed proxies IP
45 * @param int $nbAttempts Number of allowed failed attempt before the ban
46 * @param int $banDuration Ban duration in seconds
47 * @param string $banFile Path to the file containing IP bans and failures
48 * @param LoggerInterface $logger PSR-3 logger to save login attempts in log directory
50 public function __construct($trustedProxies, $nbAttempts, $banDuration, $banFile, LoggerInterface
$logger) {
51 $this->trustedProxies
= $trustedProxies;
52 $this->nbAttempts
= $nbAttempts;
53 $this->banDuration
= $banDuration;
54 $this->banFile
= $banFile;
55 $this->logger
= $logger;
61 * Handle a failed login and ban the IP after too many failed attempts
63 * @param array $server The $_SERVER array
65 public function handleFailedAttempt($server)
67 $ip = $this->getIp($server);
68 // the IP is behind a trusted forward proxy, but is not forwarded
69 // in the HTTP headers, so we do nothing
74 // increment the fail count for this IP
75 if (isset($this->failures
[$ip])) {
76 $this->failures
[$ip]++
;
78 $this->failures
[$ip] = 1;
81 if ($this->failures
[$ip] >= $this->nbAttempts
) {
82 $this->bans
[$ip] = time() +
$this->banDuration
;
83 $this->logger
->info(format_log('IP address banned from login: '. $ip, $ip));
85 $this->writeBanFile();
89 * Remove failed attempts for the provided client.
91 * @param array $server $_SERVER
93 public function clearFailures($server)
95 $ip = $this->getIp($server);
96 // the IP is behind a trusted forward proxy, but is not forwarded
97 // in the HTTP headers, so we do nothing
102 if (isset($this->failures
[$ip])) {
103 unset($this->failures
[$ip]);
105 $this->writeBanFile();
109 * Check whether the client IP is banned or not.
111 * @param array $server $_SERVER
113 * @return bool True if the IP is banned, false otherwise
115 public function isBanned($server)
117 $ip = $this->getIp($server);
118 // the IP is behind a trusted forward proxy, but is not forwarded
119 // in the HTTP headers, so we allow the authentication attempt.
124 // the user is not banned
125 if (! isset($this->bans
[$ip])) {
129 // the user is still banned
130 if ($this->bans
[$ip] > time()) {
134 // the ban has expired, the user can attempt to log in again
135 if (isset($this->failures
[$ip])) {
136 unset($this->failures
[$ip]);
138 unset($this->bans
[$ip]);
139 $this->logger
->info(format_log('Ban lifted for: '. $ip, $ip));
141 $this->writeBanFile();
146 * Retrieve the IP from $_SERVER.
147 * If the actual IP is behind an allowed reverse proxy,
148 * we try to extract the forwarded IP from HTTP headers.
150 * @param array $server $_SERVER
152 * @return string|bool The IP or false if none could be extracted
154 protected function getIp($server)
156 $ip = $server['REMOTE_ADDR'];
157 if (! in_array($ip, $this->trustedProxies
)) {
160 return getIpAddressFromProxy($server, $this->trustedProxies
);
164 * Read a file containing banned IPs
166 protected function readBanFile()
168 $data = FileUtils
::readFlatDB($this->banFile
);
169 if (isset($data['failures']) && is_array($data['failures'])) {
170 $this->failures
= $data['failures'];
173 if (isset($data['bans']) && is_array($data['bans'])) {
174 $this->bans
= $data['bans'];
179 * Write the banned IPs to a file
181 protected function writeBanFile()
183 return FileUtils
::writeFlatDB(
186 'failures' => $this->failures
,
187 'bans' => $this->bans
,
193 * Get the Failures (for UT purpose).
197 public function getFailures()
199 return $this->failures
;
203 * Get the Bans (for UT purpose).
207 public function getBans()