From 6f74ecd94a65485f9cd09434845f3c62e66fb9e5 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Mon, 2 Jan 2017 10:04:55 +0100 Subject: [PATCH] use login hook credentials as fallback If no session token is available, we can use the credentials provided by the login hook. Signed-off-by: Christoph Wurst --- .../Lib/Auth/Password/SessionCredentials.php | 12 +--- .../Authentication/LoginCredentials/Store.php | 21 +++++++ .../LoginCredentials/StoreTest.php | 63 ++++++++++++++++--- 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php b/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php index 196be05e52..30644206c2 100644 --- a/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php +++ b/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php @@ -32,27 +32,17 @@ use OCP\Authentication\Exceptions\CredentialsUnavailableException; use OCP\Authentication\LoginCredentials\IStore as CredentialsStore; use OCP\Files\Storage; use OCP\IL10N; -use OCP\ISession; use OCP\IUser; -use OCP\Security\ICrypto; /** * Username and password from login credentials, saved in session */ class SessionCredentials extends AuthMechanism { - /** @var ISession */ - protected $session; - - /** @var ICrypto */ - protected $crypto; - /** @var CredentialsStore */ private $credentialsStore; - public function __construct(IL10N $l, ISession $session, ICrypto $crypto, CredentialsStore $credentialsStore) { - $this->session = $session; - $this->crypto = $crypto; + public function __construct(IL10N $l, CredentialsStore $credentialsStore) { $this->credentialsStore = $credentialsStore; $this->setIdentifier('password::sessioncredentials') diff --git a/lib/private/Authentication/LoginCredentials/Store.php b/lib/private/Authentication/LoginCredentials/Store.php index c2b11c8e34..c50b7246f6 100644 --- a/lib/private/Authentication/LoginCredentials/Store.php +++ b/lib/private/Authentication/LoginCredentials/Store.php @@ -33,6 +33,7 @@ use OCP\Authentication\LoginCredentials\IStore; use OCP\ILogger; use OCP\ISession; use OCP\Session\Exceptions\SessionNotAvailableException; +use OCP\Util; class Store implements IStore { @@ -54,6 +55,17 @@ class Store implements IStore { $this->session = $session; $this->tokenProvider = $tokenProvider; $this->logger = $logger; + + Util::connectHook('OC_User', 'post_login', $this, 'authenticate'); + } + + /** + * Hook listener on post login + * + * @param array $params + */ + public function authenticate(array $params) { + $this->session->set('login_credentials', json_encode($params)); } /** @@ -72,6 +84,7 @@ class Store implements IStore { * @throws CredentialsUnavailableException */ public function getLoginCredentials() { + $trySession = false; try { $sessionId = $this->session->getId(); $token = $this->tokenProvider->getToken($sessionId); @@ -85,9 +98,17 @@ class Store implements IStore { $this->logger->debug('could not get login credentials because session is unavailable', ['app' => 'core']); } catch (InvalidTokenException $ex) { $this->logger->debug('could not get login credentials because the token is invalid', ['app' => 'core']); + $trySession = true; } catch (PasswordlessTokenException $ex) { $this->logger->debug('could not get login credentials because the token has no password', ['app' => 'core']); + $trySession = true; } + + if ($trySession && $this->session->exists('login_credentials')) { + $creds = json_decode($this->session->get('login_credentials')); + return new Credentials($creds->uid, $creds->uid, $creds->password); + } + // If we reach this line, an exception was thrown. throw new CredentialsUnavailableException(); } diff --git a/tests/lib/Authentication/LoginCredentials/StoreTest.php b/tests/lib/Authentication/LoginCredentials/StoreTest.php index d60add6713..56277fd0f3 100644 --- a/tests/lib/Authentication/LoginCredentials/StoreTest.php +++ b/tests/lib/Authentication/LoginCredentials/StoreTest.php @@ -34,6 +34,7 @@ use OCP\Authentication\Exceptions\CredentialsUnavailableException; use OCP\ILogger; use OCP\ISession; use OCP\Session\Exceptions\SessionNotAvailableException; +use PHPUnit_Framework_MockObject_MockObject; use Test\TestCase; class StoreTest extends TestCase { @@ -60,6 +61,26 @@ class StoreTest extends TestCase { $this->store = new Store($this->session, $this->tokenProvider, $this->logger); } + public function testAuthenticate() { + $params = [ + 'run' => true, + 'uid' => 'user123', + 'password' => 123456, + ]; + + $this->session->expects($this->once()) + ->method('set') + ->with($this->equalTo('login_credentials'), $this->equalTo(json_encode($params))); + + $this->store->authenticate($params); + } + + public function testSetSession() { + $session = $this->createMock(ISession::class); + + $this->store->setSession($session); + } + public function testGetLoginCredentials() { $uid = 'uid'; $user = 'user123'; @@ -67,21 +88,21 @@ class StoreTest extends TestCase { $token = $this->createMock(IToken::class); $this->session->expects($this->once()) ->method('getId') - ->will($this->returnValue('sess2233')); + ->willReturn('sess2233'); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('sess2233') - ->will($this->returnValue($token)); + ->willReturn($token); $token->expects($this->once()) ->method('getUID') - ->will($this->returnValue($uid)); + ->willReturn($uid); $token->expects($this->once()) ->method('getLoginName') - ->will($this->returnValue($user)); + ->willReturn($user); $this->tokenProvider->expects($this->once()) ->method('getPassword') ->with($token, 'sess2233') - ->will($this->returnValue($password)); + ->willReturn($password); $expected = new Credentials($uid, $user, $password); $creds = $this->store->getLoginCredentials(); @@ -101,7 +122,7 @@ class StoreTest extends TestCase { public function testGetLoginCredentialsInvalidToken() { $this->session->expects($this->once()) ->method('getId') - ->will($this->returnValue('sess2233')); + ->willReturn('sess2233'); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('sess2233') @@ -110,11 +131,37 @@ class StoreTest extends TestCase { $this->store->getLoginCredentials(); } - + + public function testGetLoginCredentialsInvalidTokenLoginCredentials() { + $uid = 'user987'; + $password = '7389374'; + + $this->session->expects($this->once()) + ->method('getId') + ->willReturn('sess2233'); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->with('sess2233') + ->will($this->throwException(new InvalidTokenException())); + $this->session->expects($this->once()) + ->method('exists') + ->with($this->equalTo('login_credentials')) + ->willReturn(true); + $this->session->expects($this->once()) + ->method('get') + ->with($this->equalTo('login_credentials')) + ->willReturn('{"run":true,"uid":"user987","password":"7389374"}'); + $expected = new Credentials('user987', 'user987', '7389374'); + + $actual = $this->store->getLoginCredentials(); + + $this->assertEquals($expected, $actual); + } + public function testGetLoginCredentialsPasswordlessToken() { $this->session->expects($this->once()) ->method('getId') - ->will($this->returnValue('sess2233')); + ->willReturn('sess2233'); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('sess2233')