From 698c495f34b122e1a888c338b8d0cea383a02c5b Mon Sep 17 00:00:00 2001 From: Steve Boyd <emteknetnz@gmail.com> Date: Mon, 29 Mar 2021 11:43:11 +1300 Subject: [PATCH] NEW Support for session-manager module --- .travis.yml | 7 +++ _config/session-manager.yml | 8 ++++ code/AuditHookSessionManager.php | 45 +++++++++++++++++++ tests/AuditHookSessionManagerTest.php | 64 +++++++++++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 _config/session-manager.yml create mode 100644 code/AuditHookSessionManager.php create mode 100644 tests/AuditHookSessionManagerTest.php diff --git a/.travis.yml b/.travis.yml index 0714ba5..4e2178e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,13 @@ jobs: - REQUIRE_RECIPE=4.6.x-dev - REQUIRE_MFA=4.0.x-dev - PHPUNIT_TEST=1 + - php: 7.4 + env: + - DB=MYSQL + - REQUIRE_RECIPE=4.6.x-dev + - REQUIRE_SESSION_MANAGER=1.x-dev + - PHPUNIT_TEST=1 before_script: - if [[ $REQUIRE_MFA ]]; then composer require --no-update silverstripe/mfa:"$REQUIRE_MFA"; fi + - if [[ $REQUIRE_SESSION_MANAGER ]]; then composer require --no-update silverstripe/session-manager:"$REQUIRE_SESSION_MANAGER"; fi diff --git a/_config/session-manager.yml b/_config/session-manager.yml new file mode 100644 index 0000000..289680f --- /dev/null +++ b/_config/session-manager.yml @@ -0,0 +1,8 @@ +--- +Name: auditor-session-manager +Only: + moduleexists: silverstripe/session-manager +--- +SilverStripe\SessionManager\Control\LoginSessionController: + extensions: + - SilverStripe\Auditor\AuditHookSessionManager diff --git a/code/AuditHookSessionManager.php b/code/AuditHookSessionManager.php new file mode 100644 index 0000000..4029c5e --- /dev/null +++ b/code/AuditHookSessionManager.php @@ -0,0 +1,45 @@ +<?php + +namespace SilverStripe\Auditor; + +use Psr\Log\LoggerInterface; +use SilverStripe\Core\Injector\Injector; +use SilverStripe\ORM\DataExtension; +use SilverStripe\Security\Security; +use SilverStripe\SessionManager\Model\LoginSession; + +/** + * Provides logging actions on extension hooks from certain silverstripe/session-manager actions. + */ +class AuditHookSessionManager extends DataExtension +{ + /** + * Login session for a member is being removed + * + * @param LoginSession $loginSession + */ + public function onBeforeRemoveLoginSession(LoginSession $loginSession) + { + $member = $loginSession->Member(); + $currentUser = Security::getCurrentUser(); + if (is_null($member) || $member->ID === 0 || is_null($currentUser) || $currentUser->ID === 0) { + return; + } + $this->getAuditLogger()->info(sprintf( + 'Login session (ID: %s) for Member "%s" (ID: %s) is being removed by Member "%s" (ID: %s)', + $loginSession->ID, + $member->Email ?: $member->Title, + $member->ID, + $currentUser->Email ?: $currentUser->Title, + $currentUser->ID + )); + } + + /** + * @return LoggerInterface + */ + protected function getAuditLogger() + { + return Injector::inst()->get('AuditLogger'); + } +} diff --git a/tests/AuditHookSessionManagerTest.php b/tests/AuditHookSessionManagerTest.php new file mode 100644 index 0000000..733aaee --- /dev/null +++ b/tests/AuditHookSessionManagerTest.php @@ -0,0 +1,64 @@ +<?php + +namespace SilverStripe\Auditor\Tests; + +use SilverStripe\Auditor\Tests\AuditHookTest\Logger; +use SilverStripe\Control\Controller; +use SilverStripe\Control\HTTPRequest; +use SilverStripe\Core\Injector\Injector; +use SilverStripe\Dev\SapphireTest; +use SilverStripe\Security\Member; +use SilverStripe\Security\Security; +use SilverStripe\Security\SecurityToken; +use SilverStripe\SessionManager\Control\LoginSessionController; +use SilverStripe\SessionManager\Model\LoginSession; + +class AuditHookSessionManagerTest extends SapphireTest +{ + protected $usesDatabase = true; + + /** + * @var Logger + */ + protected $writer = null; + + protected function setUp() + { + parent::setUp(); + if (!class_exists(LoginSessionController::class)) { + $this->markTestSkipped('This test requires the silverstripe/session-manager module to be installed'); + return; + } + $this->writer = new Logger; + Injector::inst()->unregisterNamedObject('AuditLogger'); + Injector::inst()->registerService($this->writer, 'AuditLogger'); + } + + public function testOnBeforeRemoveLoginSession() + { + $this->logInWithPermission('ADMIN'); + + $currentUser = Security::getCurrentUser(); + + $member = new Member(array('FirstName' => 'Joe', 'Email' => 'joe3')); + $member->write(); + $request = Controller::curr()->getRequest(); + $loginSession = LoginSession::generate($member, false, $request); + + SecurityToken::disable(); + $mockRequest = new HTTPRequest('DELETE', ''); + $mockRequest->setRouteParams(['ID' => $loginSession->ID]); + $controller = new LoginSessionController(); + $controller->removeLoginSession($mockRequest); + + $message = sprintf( + 'Login session (ID: %s) for Member "%s" (ID: %s) is being removed by Member "%s" (ID: %s)', + $loginSession->ID, + $member->Email, + $member->ID, + $currentUser->Email, + $currentUser->ID + ); + $this->assertContains($message, $this->writer->getLastMessage()); + } +}