mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-06-03 08:13:14 +08:00
Updated functionality for logging failed access
- Added testing to cover. - Linked logging into Laravel's monolog logging system and made log channel configurable. - Updated env var names to be specific to login access. - Added extra locations as to where failed logins would be captured. Related to #1881 and #728
This commit is contained in:
@ -4,6 +4,7 @@ use BookStack\Auth\Permissions\PermissionService;
|
||||
use BookStack\Auth\User;
|
||||
use BookStack\Entities\Entity;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ActivityService
|
||||
{
|
||||
@ -49,7 +50,7 @@ class ActivityService
|
||||
protected function newActivityForUser(string $key, ?int $bookId = null): Activity
|
||||
{
|
||||
return $this->activity->newInstance()->forceFill([
|
||||
'key' => strtolower($key),
|
||||
'key' => strtolower($key),
|
||||
'user_id' => $this->user->id,
|
||||
'book_id' => $bookId ?? 0,
|
||||
]);
|
||||
@ -64,8 +65,8 @@ class ActivityService
|
||||
{
|
||||
$activities = $entity->activity()->get();
|
||||
$entity->activity()->update([
|
||||
'extra' => $entity->name,
|
||||
'entity_id' => 0,
|
||||
'extra' => $entity->name,
|
||||
'entity_id' => 0,
|
||||
'entity_type' => '',
|
||||
]);
|
||||
return $activities;
|
||||
@ -99,7 +100,7 @@ class ActivityService
|
||||
$query = $this->activity->newQuery()->where('entity_type', '=', $entity->getMorphClass())
|
||||
->where('entity_id', '=', $entity->id);
|
||||
}
|
||||
|
||||
|
||||
$activity = $this->permissionService
|
||||
->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type')
|
||||
->orderBy('created_at', 'desc')
|
||||
@ -161,19 +162,18 @@ class ActivityService
|
||||
}
|
||||
|
||||
/**
|
||||
* Log failed accesses, for further processing by tools like Fail2Ban
|
||||
*
|
||||
* @param username
|
||||
* @return void
|
||||
*/
|
||||
public function logFailedAccess($username)
|
||||
* Log out a failed login attempt, Providing the given username
|
||||
* as part of the message if the '%u' string is used.
|
||||
*/
|
||||
public function logFailedLogin(string $username)
|
||||
{
|
||||
$log_msg = config('logging.failed_access_message');
|
||||
|
||||
if (!is_string($username) || !is_string($log_msg) || strlen($log_msg)<1)
|
||||
$message = config('logging.failed_login.message');
|
||||
if (!$message) {
|
||||
return;
|
||||
}
|
||||
|
||||
$log_msg = str_replace("%u", $username, $log_msg);
|
||||
error_log($log_msg, 4);
|
||||
$message = str_replace("%u", $username, $message);
|
||||
$channel = config('logging.failed_login.channel');
|
||||
Log::channel($channel)->warning($message);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
use Monolog\Handler\ErrorLogHandler;
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
|
||||
@ -73,6 +75,19 @@ return [
|
||||
'level' => 'debug',
|
||||
],
|
||||
|
||||
// Custom errorlog implementation that logs out a plain,
|
||||
// non-formatted message intended for the webserver log.
|
||||
'errorlog_plain_webserver' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => 'debug',
|
||||
'handler' => ErrorLogHandler::class,
|
||||
'handler_with' => [4],
|
||||
'formatter' => LineFormatter::class,
|
||||
'formatter_with' => [
|
||||
'format' => "%message%",
|
||||
],
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => NullHandler::class,
|
||||
@ -86,9 +101,12 @@ return [
|
||||
],
|
||||
],
|
||||
|
||||
// Failed Access Message
|
||||
// Defines the message to log into webserver logs in case of failed access,
|
||||
// for further processing by tools like Fail2Ban.
|
||||
'failed_access_message' => env('FAILED_ACCESS_MESSAGE', ''),
|
||||
|
||||
// Failed Login Message
|
||||
// Allows a configurable message to be logged when a login request fails.
|
||||
'failed_login' => [
|
||||
'message' => env('LOG_FAILED_LOGIN_MESSAGE', null),
|
||||
'channel' => env('LOG_FAILED_LOGIN_CHANNEL', 'errorlog_plain_webserver'),
|
||||
],
|
||||
|
||||
];
|
||||
|
@ -99,6 +99,7 @@ class LoginController extends Controller
|
||||
public function login(Request $request)
|
||||
{
|
||||
$this->validateLogin($request);
|
||||
$username = $request->get($this->username());
|
||||
|
||||
// If the class is using the ThrottlesLogins trait, we can automatically throttle
|
||||
// the login attempts for this application. We'll key this by the username and
|
||||
@ -107,9 +108,7 @@ class LoginController extends Controller
|
||||
$this->hasTooManyLoginAttempts($request)) {
|
||||
$this->fireLockoutEvent($request);
|
||||
|
||||
// Also log some error message
|
||||
Activity::logFailedAccess($request->get($this->username()));
|
||||
|
||||
Activity::logFailedLogin($username);
|
||||
return $this->sendLockoutResponse($request);
|
||||
}
|
||||
|
||||
@ -118,6 +117,7 @@ class LoginController extends Controller
|
||||
return $this->sendLoginResponse($request);
|
||||
}
|
||||
} catch (LoginAttemptException $exception) {
|
||||
Activity::logFailedLogin($username);
|
||||
return $this->sendLoginAttemptExceptionResponse($exception, $request);
|
||||
}
|
||||
|
||||
@ -126,9 +126,7 @@ class LoginController extends Controller
|
||||
// user surpasses their maximum number of attempts they will get locked out.
|
||||
$this->incrementLoginAttempts($request);
|
||||
|
||||
// Also log some error message
|
||||
Activity::logFailedAccess($request->get($this->username()));
|
||||
|
||||
Activity::logFailedLogin($username);
|
||||
return $this->sendFailedLoginResponse($request);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user