Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions core/Migrations/Version14000Date20180516101403.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
/**
* @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OC\Core\Migrations;

use OCP\DB\ISchemaWrapper;
use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;

class Version14000Date20180516101403 extends SimpleMigrationStep {

/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

$table = $schema->getTable('authtoken');

if (!$table->hasColumn('expires')) {
$table->addColumn('expires', 'integer', [
'notnull' => false,
'length' => 4,
'default' => null,
'unsigned' => true,
]);

return $schema;
}
return null;
}
}
2 changes: 2 additions & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@
'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php',
'OC\\Authentication\\Token\\DefaultTokenMapper' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenMapper.php',
'OC\\Authentication\\Token\\DefaultTokenProvider' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenProvider.php',
'OC\\Authentication\\Token\\ExpiredTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php',
'OC\\Authentication\\Token\\IProvider' => $baseDir . '/lib/private/Authentication/Token/IProvider.php',
'OC\\Authentication\\Token\\IToken' => $baseDir . '/lib/private/Authentication/Token/IToken.php',
'OC\\Authentication\\TwoFactorAuth\\Manager' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/Manager.php',
Expand Down Expand Up @@ -563,6 +564,7 @@
'OC\\Core\\Migrations\\Version13000Date20170926101637' => $baseDir . '/core/Migrations/Version13000Date20170926101637.php',
'OC\\Core\\Migrations\\Version14000Date20180129121024' => $baseDir . '/core/Migrations/Version14000Date20180129121024.php',
'OC\\Core\\Migrations\\Version14000Date20180404140050' => $baseDir . '/core/Migrations/Version14000Date20180404140050.php',
'OC\\Core\\Migrations\\Version14000Date20180516101403' => $baseDir . '/core/Migrations/Version14000Date20180516101403.php',
'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php',
'OC\\DB\\AdapterMySQL' => $baseDir . '/lib/private/DB/AdapterMySQL.php',
'OC\\DB\\AdapterOCI8' => $baseDir . '/lib/private/DB/AdapterOCI8.php',
Expand Down
2 changes: 2 additions & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php',
'OC\\Authentication\\Token\\DefaultTokenMapper' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenMapper.php',
'OC\\Authentication\\Token\\DefaultTokenProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenProvider.php',
'OC\\Authentication\\Token\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php',
'OC\\Authentication\\Token\\IProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IProvider.php',
'OC\\Authentication\\Token\\IToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IToken.php',
'OC\\Authentication\\TwoFactorAuth\\Manager' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/Manager.php',
Expand Down Expand Up @@ -593,6 +594,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Core\\Migrations\\Version13000Date20170926101637' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170926101637.php',
'OC\\Core\\Migrations\\Version14000Date20180129121024' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180129121024.php',
'OC\\Core\\Migrations\\Version14000Date20180404140050' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180404140050.php',
'OC\\Core\\Migrations\\Version14000Date20180516101403' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180516101403.php',
'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php',
'OC\\DB\\AdapterMySQL' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterMySQL.php',
'OC\\DB\\AdapterOCI8' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterOCI8.php',
Expand Down
41 changes: 41 additions & 0 deletions lib/private/Authentication/Exceptions/ExpiredTokenException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\Authentication\Token;

use OC\Authentication\Exceptions\InvalidTokenException;

class ExpiredTokenException extends InvalidTokenException {
/** @var IToken */
private $token;

public function __construct(IToken $token) {
parent::__construct();

$this->token = $token;
}

public function getToken(): IToken {
return $this->token;
}
}
15 changes: 15 additions & 0 deletions lib/private/Authentication/Token/DefaultToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class DefaultToken extends Entity implements IToken {
/** @var string */
protected $scope;

/** @var int */
protected $expires;

public function __construct() {
$this->addType('uid', 'string');
$this->addType('loginName', 'string');
Expand All @@ -81,6 +84,7 @@ public function __construct() {
$this->addType('lastActivity', 'int');
$this->addType('lastCheck', 'int');
$this->addType('scope', 'string');
$this->addType('expires', 'int');
}

public function getId(): int {
Expand Down Expand Up @@ -179,4 +183,15 @@ public function setToken(string $token) {
public function setPassword(string $password = null) {
parent::setPassword($password);
}

public function setExpires($expires) {
parent::setExpires($expires);
}

/**
* @return int|null
*/
public function getExpires() {
return parent::getExpires();
}
}
6 changes: 3 additions & 3 deletions lib/private/Authentication/Token/DefaultTokenMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public function invalidateOld(int $olderThan, int $remember = IToken::DO_NOT_REM
public function getToken(string $token): DefaultToken {
/* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
$result = $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'remember', 'token', 'last_activity', 'last_check', 'scope')
$result = $qb->select('*')
->from('authtoken')
->where($qb->expr()->eq('token', $qb->createNamedParameter($token)))
->execute();
Expand All @@ -102,7 +102,7 @@ public function getToken(string $token): DefaultToken {
public function getTokenById(int $id): DefaultToken {
/* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
$result = $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'token', 'last_activity', 'last_check', 'scope')
$result = $qb->select('*')
->from('authtoken')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->execute();
Expand All @@ -127,7 +127,7 @@ public function getTokenById(int $id): DefaultToken {
public function getTokenByUser(IUser $user): array {
/* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
$qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'remember', 'token', 'last_activity', 'last_check', 'scope')
$qb->select('*')
->from('authtoken')
->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
->setMaxResults(1000);
Expand Down
18 changes: 16 additions & 2 deletions lib/private/Authentication/Token/DefaultTokenProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,29 +161,43 @@ public function getTokenByUser(IUser $user): array {
*
* @param string $tokenId
* @throws InvalidTokenException
* @throws ExpiredTokenException
* @return IToken
*/
public function getToken(string $tokenId): IToken {
try {
return $this->mapper->getToken($this->hashToken($tokenId));
$token = $this->mapper->getToken($this->hashToken($tokenId));
} catch (DoesNotExistException $ex) {
throw new InvalidTokenException();
}

if ($token->getExpires() !== null && $token->getExpires() < $this->time->getTime()) {
throw new ExpiredTokenException($token);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add this to the PHPDocs?

}

return $token;
}

/**
* Get a token by token id
*
* @param int $tokenId
* @throws InvalidTokenException
* @throws ExpiredTokenException
* @return IToken
*/
public function getTokenById(int $tokenId): IToken {
try {
return $this->mapper->getTokenById($tokenId);
$token = $this->mapper->getTokenById($tokenId);
} catch (DoesNotExistException $ex) {
throw new InvalidTokenException();
}

if ($token->getExpires() !== null && $token->getExpires() < $this->time->getTime()) {
throw new ExpiredTokenException($token);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done..

}

return $token;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions lib/private/Authentication/Token/IProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public function generateToken(string $token,
*
* @param string $tokenId
* @throws InvalidTokenException
* @throws ExpiredTokenException
* @return IToken
*/
public function getToken(string $tokenId): IToken;
Expand All @@ -67,6 +68,7 @@ public function getToken(string $tokenId): IToken;
*
* @param int $tokenId
* @throws InvalidTokenException
* @throws ExpiredTokenException
* @return IToken
*/
public function getTokenById(int $tokenId): IToken;
Expand Down
7 changes: 7 additions & 0 deletions lib/private/Authentication/Token/IToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,11 @@ public function setToken(string $token);
* @param string $password
*/
public function setPassword(string $password);

/**
* Set the expiration time of the token
*
* @param int|null $expires
*/
public function setExpires($expires);
}
75 changes: 75 additions & 0 deletions tests/lib/Authentication/Token/DefaultTokenProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use OC\Authentication\Token\DefaultToken;
use OC\Authentication\Token\DefaultTokenMapper;
use OC\Authentication\Token\DefaultTokenProvider;
use OC\Authentication\Token\ExpiredTokenException;
use OC\Authentication\Token\IToken;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Utility\ITimeFactory;
Expand Down Expand Up @@ -395,6 +396,63 @@ public function testRenewSessionTokenWithPassword() {
$this->tokenProvider->renewSessionToken('oldId', 'newId');
}

public function testGetToken() {
$token = new DefaultToken();

$this->config->method('getSystemValue')
->with('secret')
->willReturn('mysecret');

$this->mapper->method('getToken')
->with(
$this->callback(function (string $token) {
return hash('sha512', 'unhashedTokenmysecret') === $token;
})
)->willReturn($token);

$this->assertSame($token, $this->tokenProvider->getToken('unhashedToken'));
}

public function testGetInvalidToken() {
$this->expectException(InvalidTokenException::class);

$this->config->method('getSystemValue')
->with('secret')
->willReturn('mysecret');

$this->mapper->method('getToken')
->with(
$this->callback(function (string $token) {
return hash('sha512', 'unhashedTokenmysecret') === $token;
})
)->willThrowException(new InvalidTokenException());

$this->tokenProvider->getToken('unhashedToken');
}

public function testGetExpiredToken() {
$token = new DefaultToken();
$token->setExpires(42);

$this->config->method('getSystemValue')
->with('secret')
->willReturn('mysecret');

$this->mapper->method('getToken')
->with(
$this->callback(function (string $token) {
return hash('sha512', 'unhashedTokenmysecret') === $token;
})
)->willReturn($token);

try {
$this->tokenProvider->getToken('unhashedToken');
} catch (ExpiredTokenException $e) {
$this->assertSame($token, $e->getToken());
}

}

public function testGetTokenById() {
$token = $this->createMock(DefaultToken::class);

Expand All @@ -417,6 +475,23 @@ public function testGetInvalidTokenById() {
$this->tokenProvider->getTokenById(42);
}

public function testGetExpiredTokenById() {
$token = new DefaultToken();
$token->setExpires(42);

$this->mapper->expects($this->once())
->method('getTokenById')
->with($this->equalTo(42))
->willReturn($token);

try {
$this->tokenProvider->getTokenById(42);
$this->fail();
} catch (ExpiredTokenException $e) {
$this->assertSame($token, $e->getToken());
}
}

public function testRotate() {
$token = new DefaultToken();
$token->setPassword('oldencryptedpassword');
Expand Down
2 changes: 1 addition & 1 deletion version.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
// when updating major/minor version number.

$OC_Version = array(14, 0, 0, 3);
$OC_Version = array(14, 0, 0, 4);

// The human readable string
$OC_VersionString = '14.0.0 alpha';
Expand Down