1919use OCP \AppFramework \Http ;
2020use OCP \AppFramework \Http \JSONResponse ;
2121use OCP \AppFramework \Utility \ITimeFactory ;
22+ use OCP \IDBConnection ;
2223use OCP \IRequest ;
2324use OCP \Security \Bruteforce \IThrottler ;
2425use OCP \Security \ICrypto ;
@@ -52,6 +53,8 @@ class OauthApiControllerTest extends TestCase {
5253 private $ logger ;
5354 /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
5455 private $ timeFactory ;
56+ /** @var IDBConnection|\PHPUnit\Framework\MockObject\MockObject */
57+ private $ db ;
5558 /** @var OauthApiController */
5659 private $ oauthApiController ;
5760
@@ -68,6 +71,7 @@ protected function setUp(): void {
6871 $ this ->throttler = $ this ->createMock (IThrottler::class);
6972 $ this ->logger = $ this ->createMock (LoggerInterface::class);
7073 $ this ->timeFactory = $ this ->createMock (ITimeFactory::class);
74+ $ this ->db = $ this ->createMock (IDBConnection::class);
7175
7276 $ this ->oauthApiController = new OauthApiController (
7377 'oauth2 ' ,
@@ -80,7 +84,8 @@ protected function setUp(): void {
8084 $ this ->time ,
8185 $ this ->logger ,
8286 $ this ->throttler ,
83- $ this ->timeFactory
87+ $ this ->timeFactory ,
88+ $ this ->db ,
8489 );
8590 }
8691
@@ -315,6 +320,7 @@ public function testRefreshTokenInvalidAppToken(): void {
315320
316321 public function testRefreshTokenValidAppToken (): void {
317322 $ accessToken = new AccessToken ();
323+ $ accessToken ->setId (21 );
318324 $ accessToken ->setClientId (42 );
319325 $ accessToken ->setTokenId (1337 );
320326 $ accessToken ->setEncryptedToken ('encryptedToken ' );
@@ -366,6 +372,18 @@ public function testRefreshTokenValidAppToken(): void {
366372 $ this ->time ->method ('getTime ' )
367373 ->willReturn (1000 );
368374
375+ $ this ->db ->expects ($ this ->once ())
376+ ->method ('beginTransaction ' );
377+
378+ $ this ->db ->expects ($ this ->once ())
379+ ->method ('commit ' );
380+
381+ $ this ->db ->expects ($ this ->never ())
382+ ->method ('rollBack ' );
383+
384+ $ this ->tokenProvider ->expects ($ this ->never ())
385+ ->method ('invalidateToken ' );
386+
369387 $ this ->tokenProvider ->expects ($ this ->once ())
370388 ->method ('updateToken ' )
371389 ->with (
@@ -379,7 +397,7 @@ public function testRefreshTokenValidAppToken(): void {
379397 ->willReturn ('newEncryptedToken ' );
380398
381399 $ this ->accessTokenMapper ->expects ($ this ->once ())
382- ->method ('update ' )
400+ ->method ('rotateToken ' )
383401 ->with (
384402 $ this ->callback (function (AccessToken $ token ) {
385403 return $ token ->getHashedCode () === hash ('sha512 ' , 'random128 ' ) &&
@@ -411,6 +429,7 @@ public function testRefreshTokenValidAppToken(): void {
411429
412430 public function testRefreshTokenValidAppTokenBasicAuth (): void {
413431 $ accessToken = new AccessToken ();
432+ $ accessToken ->setId (21 );
414433 $ accessToken ->setClientId (42 );
415434 $ accessToken ->setTokenId (1337 );
416435 $ accessToken ->setEncryptedToken ('encryptedToken ' );
@@ -462,6 +481,18 @@ public function testRefreshTokenValidAppTokenBasicAuth(): void {
462481 $ this ->time ->method ('getTime ' )
463482 ->willReturn (1000 );
464483
484+ $ this ->db ->expects ($ this ->once ())
485+ ->method ('beginTransaction ' );
486+
487+ $ this ->db ->expects ($ this ->once ())
488+ ->method ('commit ' );
489+
490+ $ this ->db ->expects ($ this ->never ())
491+ ->method ('rollBack ' );
492+
493+ $ this ->tokenProvider ->expects ($ this ->never ())
494+ ->method ('invalidateToken ' );
495+
465496 $ this ->tokenProvider ->expects ($ this ->once ())
466497 ->method ('updateToken ' )
467498 ->with (
@@ -475,7 +506,7 @@ public function testRefreshTokenValidAppTokenBasicAuth(): void {
475506 ->willReturn ('newEncryptedToken ' );
476507
477508 $ this ->accessTokenMapper ->expects ($ this ->once ())
478- ->method ('update ' )
509+ ->method ('rotateToken ' )
479510 ->with (
480511 $ this ->callback (function (AccessToken $ token ) {
481512 return $ token ->getHashedCode () === hash ('sha512 ' , 'random128 ' ) &&
@@ -510,6 +541,7 @@ public function testRefreshTokenValidAppTokenBasicAuth(): void {
510541
511542 public function testRefreshTokenExpiredAppToken (): void {
512543 $ accessToken = new AccessToken ();
544+ $ accessToken ->setId (21 );
513545 $ accessToken ->setClientId (42 );
514546 $ accessToken ->setTokenId (1337 );
515547 $ accessToken ->setEncryptedToken ('encryptedToken ' );
@@ -561,6 +593,18 @@ public function testRefreshTokenExpiredAppToken(): void {
561593 $ this ->time ->method ('getTime ' )
562594 ->willReturn (1000 );
563595
596+ $ this ->db ->expects ($ this ->once ())
597+ ->method ('beginTransaction ' );
598+
599+ $ this ->db ->expects ($ this ->once ())
600+ ->method ('commit ' );
601+
602+ $ this ->db ->expects ($ this ->never ())
603+ ->method ('rollBack ' );
604+
605+ $ this ->tokenProvider ->expects ($ this ->never ())
606+ ->method ('invalidateToken ' );
607+
564608 $ this ->tokenProvider ->expects ($ this ->once ())
565609 ->method ('updateToken ' )
566610 ->with (
@@ -574,7 +618,7 @@ public function testRefreshTokenExpiredAppToken(): void {
574618 ->willReturn ('newEncryptedToken ' );
575619
576620 $ this ->accessTokenMapper ->expects ($ this ->once ())
577- ->method ('update ' )
621+ ->method ('rotateToken ' )
578622 ->with (
579623 $ this ->callback (function (AccessToken $ token ) {
580624 return $ token ->getHashedCode () === hash ('sha512 ' , 'random128 ' ) &&
@@ -603,4 +647,100 @@ public function testRefreshTokenExpiredAppToken(): void {
603647
604648 $ this ->assertEquals ($ expected , $ this ->oauthApiController ->getToken ('refresh_token ' , null , 'validrefresh ' , 'clientId ' , 'clientSecret ' ));
605649 }
650+
651+ public function testRefreshTokenRedeemedConcurrently (): void {
652+ $ expected = new JSONResponse ([
653+ 'error ' => 'invalid_request ' ,
654+ ], Http::STATUS_BAD_REQUEST );
655+ $ expected ->throttle (['invalid_request ' => 'token already redeemed ' ]);
656+
657+ $ accessToken = new AccessToken ();
658+ $ accessToken ->setId (21 );
659+ $ accessToken ->setClientId (42 );
660+ $ accessToken ->setTokenId (1337 );
661+ $ accessToken ->setEncryptedToken ('encryptedToken ' );
662+
663+ $ this ->accessTokenMapper ->method ('getByCode ' )
664+ ->with ('validrefresh ' )
665+ ->willReturn ($ accessToken );
666+
667+ $ client = new Client ();
668+ $ client ->setClientIdentifier ('clientId ' );
669+ $ client ->setSecret (bin2hex ('hashedClientSecret ' ));
670+ $ this ->clientMapper ->method ('getByUid ' )
671+ ->with (42 )
672+ ->willReturn ($ client );
673+
674+ $ this ->crypto
675+ ->method ('decrypt ' )
676+ ->with ('encryptedToken ' )
677+ ->willReturn ('decryptedToken ' );
678+
679+ $ this ->crypto
680+ ->method ('calculateHMAC ' )
681+ ->with ('clientSecret ' )
682+ ->willReturn ('hashedClientSecret ' );
683+
684+ $ appToken = new PublicKeyToken ();
685+ $ appToken ->setUid ('userId ' );
686+ $ this ->tokenProvider ->method ('getTokenById ' )
687+ ->with (1337 )
688+ ->willReturn ($ appToken );
689+
690+ $ this ->secureRandom ->method ('generate ' )
691+ ->willReturnCallback (function ($ len ) {
692+ return 'random ' . $ len ;
693+ });
694+
695+ $ this ->tokenProvider ->expects ($ this ->once ())
696+ ->method ('rotate ' )
697+ ->with (
698+ $ appToken ,
699+ 'decryptedToken ' ,
700+ 'random72 '
701+ )->willReturn ($ appToken );
702+
703+ $ this ->time ->method ('getTime ' )
704+ ->willReturn (1000 );
705+
706+ $ this ->tokenProvider ->expects ($ this ->once ())
707+ ->method ('updateToken ' )
708+ ->with ($ this ->isInstanceOf (PublicKeyToken::class));
709+
710+ $ this ->crypto ->method ('encrypt ' )
711+ ->with ('random72 ' , 'random128 ' )
712+ ->willReturn ('newEncryptedToken ' );
713+
714+ $ this ->db ->expects ($ this ->once ())
715+ ->method ('beginTransaction ' );
716+
717+ $ this ->db ->expects ($ this ->never ())
718+ ->method ('commit ' );
719+
720+ $ this ->db ->expects ($ this ->exactly (2 ))
721+ ->method ('inTransaction ' )
722+ ->willReturnOnConsecutiveCalls (true , false );
723+
724+ $ this ->db ->expects ($ this ->once ())
725+ ->method ('rollBack ' );
726+
727+ $ this ->tokenProvider ->expects ($ this ->once ())
728+ ->method ('invalidateToken ' )
729+ ->with ('random72 ' );
730+
731+ $ this ->accessTokenMapper ->expects ($ this ->once ())
732+ ->method ('rotateToken ' )
733+ ->with (
734+ 21 ,
735+ 'validrefresh ' ,
736+ 'random128 ' ,
737+ 'newEncryptedToken ' ,
738+ false ,
739+ )->willReturn (0 );
740+
741+ $ this ->throttler ->expects ($ this ->never ())
742+ ->method ('resetDelay ' );
743+
744+ $ this ->assertEquals ($ expected , $ this ->oauthApiController ->getToken ('refresh_token ' , null , 'validrefresh ' , 'clientId ' , 'clientSecret ' ));
745+ }
606746}
0 commit comments