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 <christoph@winzerhof-wurst.at>
This commit is contained in:
Christoph Wurst 2017-01-02 10:04:55 +01:00 committed by Roeland Jago Douma
parent e4abb9cb6e
commit 6f74ecd94a
No known key found for this signature in database
GPG Key ID: F941078878347C0C
3 changed files with 77 additions and 19 deletions

View File

@ -32,27 +32,17 @@ use OCP\Authentication\Exceptions\CredentialsUnavailableException;
use OCP\Authentication\LoginCredentials\IStore as CredentialsStore; use OCP\Authentication\LoginCredentials\IStore as CredentialsStore;
use OCP\Files\Storage; use OCP\Files\Storage;
use OCP\IL10N; use OCP\IL10N;
use OCP\ISession;
use OCP\IUser; use OCP\IUser;
use OCP\Security\ICrypto;
/** /**
* Username and password from login credentials, saved in session * Username and password from login credentials, saved in session
*/ */
class SessionCredentials extends AuthMechanism { class SessionCredentials extends AuthMechanism {
/** @var ISession */
protected $session;
/** @var ICrypto */
protected $crypto;
/** @var CredentialsStore */ /** @var CredentialsStore */
private $credentialsStore; private $credentialsStore;
public function __construct(IL10N $l, ISession $session, ICrypto $crypto, CredentialsStore $credentialsStore) { public function __construct(IL10N $l, CredentialsStore $credentialsStore) {
$this->session = $session;
$this->crypto = $crypto;
$this->credentialsStore = $credentialsStore; $this->credentialsStore = $credentialsStore;
$this->setIdentifier('password::sessioncredentials') $this->setIdentifier('password::sessioncredentials')

View File

@ -33,6 +33,7 @@ use OCP\Authentication\LoginCredentials\IStore;
use OCP\ILogger; use OCP\ILogger;
use OCP\ISession; use OCP\ISession;
use OCP\Session\Exceptions\SessionNotAvailableException; use OCP\Session\Exceptions\SessionNotAvailableException;
use OCP\Util;
class Store implements IStore { class Store implements IStore {
@ -54,6 +55,17 @@ class Store implements IStore {
$this->session = $session; $this->session = $session;
$this->tokenProvider = $tokenProvider; $this->tokenProvider = $tokenProvider;
$this->logger = $logger; $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 * @throws CredentialsUnavailableException
*/ */
public function getLoginCredentials() { public function getLoginCredentials() {
$trySession = false;
try { try {
$sessionId = $this->session->getId(); $sessionId = $this->session->getId();
$token = $this->tokenProvider->getToken($sessionId); $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']); $this->logger->debug('could not get login credentials because session is unavailable', ['app' => 'core']);
} catch (InvalidTokenException $ex) { } catch (InvalidTokenException $ex) {
$this->logger->debug('could not get login credentials because the token is invalid', ['app' => 'core']); $this->logger->debug('could not get login credentials because the token is invalid', ['app' => 'core']);
$trySession = true;
} catch (PasswordlessTokenException $ex) { } catch (PasswordlessTokenException $ex) {
$this->logger->debug('could not get login credentials because the token has no password', ['app' => 'core']); $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. // If we reach this line, an exception was thrown.
throw new CredentialsUnavailableException(); throw new CredentialsUnavailableException();
} }

View File

@ -34,6 +34,7 @@ use OCP\Authentication\Exceptions\CredentialsUnavailableException;
use OCP\ILogger; use OCP\ILogger;
use OCP\ISession; use OCP\ISession;
use OCP\Session\Exceptions\SessionNotAvailableException; use OCP\Session\Exceptions\SessionNotAvailableException;
use PHPUnit_Framework_MockObject_MockObject;
use Test\TestCase; use Test\TestCase;
class StoreTest extends TestCase { class StoreTest extends TestCase {
@ -60,6 +61,26 @@ class StoreTest extends TestCase {
$this->store = new Store($this->session, $this->tokenProvider, $this->logger); $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() { public function testGetLoginCredentials() {
$uid = 'uid'; $uid = 'uid';
$user = 'user123'; $user = 'user123';
@ -67,21 +88,21 @@ class StoreTest extends TestCase {
$token = $this->createMock(IToken::class); $token = $this->createMock(IToken::class);
$this->session->expects($this->once()) $this->session->expects($this->once())
->method('getId') ->method('getId')
->will($this->returnValue('sess2233')); ->willReturn('sess2233');
$this->tokenProvider->expects($this->once()) $this->tokenProvider->expects($this->once())
->method('getToken') ->method('getToken')
->with('sess2233') ->with('sess2233')
->will($this->returnValue($token)); ->willReturn($token);
$token->expects($this->once()) $token->expects($this->once())
->method('getUID') ->method('getUID')
->will($this->returnValue($uid)); ->willReturn($uid);
$token->expects($this->once()) $token->expects($this->once())
->method('getLoginName') ->method('getLoginName')
->will($this->returnValue($user)); ->willReturn($user);
$this->tokenProvider->expects($this->once()) $this->tokenProvider->expects($this->once())
->method('getPassword') ->method('getPassword')
->with($token, 'sess2233') ->with($token, 'sess2233')
->will($this->returnValue($password)); ->willReturn($password);
$expected = new Credentials($uid, $user, $password); $expected = new Credentials($uid, $user, $password);
$creds = $this->store->getLoginCredentials(); $creds = $this->store->getLoginCredentials();
@ -101,7 +122,7 @@ class StoreTest extends TestCase {
public function testGetLoginCredentialsInvalidToken() { public function testGetLoginCredentialsInvalidToken() {
$this->session->expects($this->once()) $this->session->expects($this->once())
->method('getId') ->method('getId')
->will($this->returnValue('sess2233')); ->willReturn('sess2233');
$this->tokenProvider->expects($this->once()) $this->tokenProvider->expects($this->once())
->method('getToken') ->method('getToken')
->with('sess2233') ->with('sess2233')
@ -110,11 +131,37 @@ class StoreTest extends TestCase {
$this->store->getLoginCredentials(); $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() { public function testGetLoginCredentialsPasswordlessToken() {
$this->session->expects($this->once()) $this->session->expects($this->once())
->method('getId') ->method('getId')
->will($this->returnValue('sess2233')); ->willReturn('sess2233');
$this->tokenProvider->expects($this->once()) $this->tokenProvider->expects($this->once())
->method('getToken') ->method('getToken')
->with('sess2233') ->with('sess2233')