Reset bruteforce on token refresh OAuth
When using atoken obtained via OAuth the token expires. Resulting in brute force attempts hitting the requesting IP. This resets the brute force attempts for that UID on a valid refresh of the token. Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
This commit is contained in:
parent
963d968f06
commit
75456b057d
|
@ -24,6 +24,7 @@ namespace OCA\OAuth2\Controller;
|
||||||
use OC\Authentication\Exceptions\InvalidTokenException;
|
use OC\Authentication\Exceptions\InvalidTokenException;
|
||||||
use OC\Authentication\Token\ExpiredTokenException;
|
use OC\Authentication\Token\ExpiredTokenException;
|
||||||
use OC\Authentication\Token\IProvider as TokenProvider;
|
use OC\Authentication\Token\IProvider as TokenProvider;
|
||||||
|
use OC\Security\Bruteforce\Throttler;
|
||||||
use OCA\OAuth2\Db\AccessTokenMapper;
|
use OCA\OAuth2\Db\AccessTokenMapper;
|
||||||
use OCA\OAuth2\Db\ClientMapper;
|
use OCA\OAuth2\Db\ClientMapper;
|
||||||
use OCA\OAuth2\Exceptions\AccessTokenNotFoundException;
|
use OCA\OAuth2\Exceptions\AccessTokenNotFoundException;
|
||||||
|
@ -49,6 +50,8 @@ class OauthApiController extends Controller {
|
||||||
private $secureRandom;
|
private $secureRandom;
|
||||||
/** @var ITimeFactory */
|
/** @var ITimeFactory */
|
||||||
private $time;
|
private $time;
|
||||||
|
/** @var Throttler */
|
||||||
|
private $throttler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $appName
|
* @param string $appName
|
||||||
|
@ -59,6 +62,7 @@ class OauthApiController extends Controller {
|
||||||
* @param TokenProvider $tokenProvider
|
* @param TokenProvider $tokenProvider
|
||||||
* @param ISecureRandom $secureRandom
|
* @param ISecureRandom $secureRandom
|
||||||
* @param ITimeFactory $time
|
* @param ITimeFactory $time
|
||||||
|
* @param Throttler $throttler
|
||||||
*/
|
*/
|
||||||
public function __construct($appName,
|
public function __construct($appName,
|
||||||
IRequest $request,
|
IRequest $request,
|
||||||
|
@ -67,7 +71,8 @@ class OauthApiController extends Controller {
|
||||||
ClientMapper $clientMapper,
|
ClientMapper $clientMapper,
|
||||||
TokenProvider $tokenProvider,
|
TokenProvider $tokenProvider,
|
||||||
ISecureRandom $secureRandom,
|
ISecureRandom $secureRandom,
|
||||||
ITimeFactory $time) {
|
ITimeFactory $time,
|
||||||
|
Throttler $throttler) {
|
||||||
parent::__construct($appName, $request);
|
parent::__construct($appName, $request);
|
||||||
$this->crypto = $crypto;
|
$this->crypto = $crypto;
|
||||||
$this->accessTokenMapper = $accessTokenMapper;
|
$this->accessTokenMapper = $accessTokenMapper;
|
||||||
|
@ -75,6 +80,7 @@ class OauthApiController extends Controller {
|
||||||
$this->tokenProvider = $tokenProvider;
|
$this->tokenProvider = $tokenProvider;
|
||||||
$this->secureRandom = $secureRandom;
|
$this->secureRandom = $secureRandom;
|
||||||
$this->time = $time;
|
$this->time = $time;
|
||||||
|
$this->throttler = $throttler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,6 +170,8 @@ class OauthApiController extends Controller {
|
||||||
$accessToken->setEncryptedToken($this->crypto->encrypt($newToken, $newCode));
|
$accessToken->setEncryptedToken($this->crypto->encrypt($newToken, $newCode));
|
||||||
$this->accessTokenMapper->update($accessToken);
|
$this->accessTokenMapper->update($accessToken);
|
||||||
|
|
||||||
|
$this->throttler->resetDelay($this->request->getRemoteAddress(), 'login', ['user' => $appToken->getUID()]);
|
||||||
|
|
||||||
return new JSONResponse(
|
return new JSONResponse(
|
||||||
[
|
[
|
||||||
'access_token' => $newToken,
|
'access_token' => $newToken,
|
||||||
|
|
|
@ -27,6 +27,7 @@ use OC\Authentication\Token\DefaultTokenMapper;
|
||||||
use OC\Authentication\Token\ExpiredTokenException;
|
use OC\Authentication\Token\ExpiredTokenException;
|
||||||
use OC\Authentication\Token\IProvider as TokenProvider;
|
use OC\Authentication\Token\IProvider as TokenProvider;
|
||||||
use OC\Authentication\Token\IToken;
|
use OC\Authentication\Token\IToken;
|
||||||
|
use OC\Security\Bruteforce\Throttler;
|
||||||
use OCA\OAuth2\Controller\OauthApiController;
|
use OCA\OAuth2\Controller\OauthApiController;
|
||||||
use OCA\OAuth2\Db\AccessToken;
|
use OCA\OAuth2\Db\AccessToken;
|
||||||
use OCA\OAuth2\Db\AccessTokenMapper;
|
use OCA\OAuth2\Db\AccessTokenMapper;
|
||||||
|
@ -57,6 +58,8 @@ class OauthApiControllerTest extends TestCase {
|
||||||
private $secureRandom;
|
private $secureRandom;
|
||||||
/** @var ITimeFactory|\PHPUnit_Framework_MockObject_MockObject */
|
/** @var ITimeFactory|\PHPUnit_Framework_MockObject_MockObject */
|
||||||
private $time;
|
private $time;
|
||||||
|
/** @var Throttler|\PHPUnit_Framework_MockObject_MockObject */
|
||||||
|
private $throttler;
|
||||||
/** @var OauthApiController */
|
/** @var OauthApiController */
|
||||||
private $oauthApiController;
|
private $oauthApiController;
|
||||||
|
|
||||||
|
@ -70,6 +73,7 @@ class OauthApiControllerTest extends TestCase {
|
||||||
$this->tokenProvider = $this->createMock(TokenProvider::class);
|
$this->tokenProvider = $this->createMock(TokenProvider::class);
|
||||||
$this->secureRandom = $this->createMock(ISecureRandom::class);
|
$this->secureRandom = $this->createMock(ISecureRandom::class);
|
||||||
$this->time = $this->createMock(ITimeFactory::class);
|
$this->time = $this->createMock(ITimeFactory::class);
|
||||||
|
$this->throttler = $this->createMock(Throttler::class);
|
||||||
|
|
||||||
$this->oauthApiController = new OauthApiController(
|
$this->oauthApiController = new OauthApiController(
|
||||||
'oauth2',
|
'oauth2',
|
||||||
|
@ -79,7 +83,8 @@ class OauthApiControllerTest extends TestCase {
|
||||||
$this->clientMapper,
|
$this->clientMapper,
|
||||||
$this->tokenProvider,
|
$this->tokenProvider,
|
||||||
$this->secureRandom,
|
$this->secureRandom,
|
||||||
$this->time
|
$this->time,
|
||||||
|
$this->throttler
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +291,17 @@ class OauthApiControllerTest extends TestCase {
|
||||||
'user_id' => 'userId',
|
'user_id' => 'userId',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->request->method('getRemoteAddress')
|
||||||
|
->willReturn('1.2.3.4');
|
||||||
|
|
||||||
|
$this->throttler->expects($this->once())
|
||||||
|
->method('resetDelay')
|
||||||
|
->with(
|
||||||
|
'1.2.3.4',
|
||||||
|
'login',
|
||||||
|
['user' => 'userId']
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', 'clientId', 'clientSecret'));
|
$this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', 'clientId', 'clientSecret'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,6 +386,17 @@ class OauthApiControllerTest extends TestCase {
|
||||||
$this->request->server['PHP_AUTH_USER'] = 'clientId';
|
$this->request->server['PHP_AUTH_USER'] = 'clientId';
|
||||||
$this->request->server['PHP_AUTH_PW'] = 'clientSecret';
|
$this->request->server['PHP_AUTH_PW'] = 'clientSecret';
|
||||||
|
|
||||||
|
$this->request->method('getRemoteAddress')
|
||||||
|
->willReturn('1.2.3.4');
|
||||||
|
|
||||||
|
$this->throttler->expects($this->once())
|
||||||
|
->method('resetDelay')
|
||||||
|
->with(
|
||||||
|
'1.2.3.4',
|
||||||
|
'login',
|
||||||
|
['user' => 'userId']
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', null, null));
|
$this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,6 +478,17 @@ class OauthApiControllerTest extends TestCase {
|
||||||
'user_id' => 'userId',
|
'user_id' => 'userId',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->request->method('getRemoteAddress')
|
||||||
|
->willReturn('1.2.3.4');
|
||||||
|
|
||||||
|
$this->throttler->expects($this->once())
|
||||||
|
->method('resetDelay')
|
||||||
|
->with(
|
||||||
|
'1.2.3.4',
|
||||||
|
'login',
|
||||||
|
['user' => 'userId']
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', 'clientId', 'clientSecret'));
|
$this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', 'clientId', 'clientSecret'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -758,7 +758,7 @@ class Server extends ServerContainer implements IServerContainer {
|
||||||
$this->registerService('TrustedDomainHelper', function ($c) {
|
$this->registerService('TrustedDomainHelper', function ($c) {
|
||||||
return new TrustedDomainHelper($this->getConfig());
|
return new TrustedDomainHelper($this->getConfig());
|
||||||
});
|
});
|
||||||
$this->registerService('Throttler', function (Server $c) {
|
$this->registerService(Throttler::class, function (Server $c) {
|
||||||
return new Throttler(
|
return new Throttler(
|
||||||
$c->getDatabaseConnection(),
|
$c->getDatabaseConnection(),
|
||||||
new TimeFactory(),
|
new TimeFactory(),
|
||||||
|
@ -766,6 +766,7 @@ class Server extends ServerContainer implements IServerContainer {
|
||||||
$c->getConfig()
|
$c->getConfig()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
$this->registerAlias('Throttler', Throttler::class);
|
||||||
$this->registerService('IntegrityCodeChecker', function (Server $c) {
|
$this->registerService('IntegrityCodeChecker', function (Server $c) {
|
||||||
// IConfig and IAppManager requires a working database. This code
|
// IConfig and IAppManager requires a working database. This code
|
||||||
// might however be called when ownCloud is not yet setup.
|
// might however be called when ownCloud is not yet setup.
|
||||||
|
|
Loading…
Reference in New Issue