2020use OCP \AppFramework \Http ;
2121use OCP \AppFramework \Http \JSONResponse ;
2222use OCP \AppFramework \Utility \ITimeFactory ;
23+ use OCP \IDBConnection ;
2324use OCP \IRequest ;
2425use OCP \Security \Bruteforce \IThrottler ;
2526use OCP \Security \ICrypto ;
@@ -53,6 +54,8 @@ class OauthApiControllerTest extends TestCase {
5354 private $ logger ;
5455 /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
5556 private $ timeFactory ;
57+ /** @var IDBConnection|\PHPUnit\Framework\MockObject\MockObject */
58+ private $ db ;
5659 /** @var OauthApiController */
5760 private $ oauthApiController ;
5861
@@ -69,6 +72,7 @@ protected function setUp(): void {
6972 $ this ->throttler = $ this ->createMock (IThrottler::class);
7073 $ this ->logger = $ this ->createMock (LoggerInterface::class);
7174 $ this ->timeFactory = $ this ->createMock (ITimeFactory::class);
75+ $ this ->db = $ this ->createMock (IDBConnection::class);
7276
7377 $ this ->oauthApiController = new OauthApiController (
7478 'oauth2 ' ,
@@ -81,7 +85,8 @@ protected function setUp(): void {
8185 $ this ->time ,
8286 $ this ->logger ,
8387 $ this ->throttler ,
84- $ this ->timeFactory
88+ $ this ->timeFactory ,
89+ $ this ->db ,
8590 );
8691 }
8792
@@ -316,6 +321,7 @@ public function testRefreshTokenInvalidAppToken(): void {
316321
317322 public function testRefreshTokenValidAppToken (): void {
318323 $ accessToken = new AccessToken ();
324+ $ accessToken ->setId (21 );
319325 $ accessToken ->setClientId (42 );
320326 $ accessToken ->setTokenId (1337 );
321327 $ accessToken ->setEncryptedToken ('encryptedToken ' );
@@ -367,6 +373,18 @@ public function testRefreshTokenValidAppToken(): void {
367373 $ this ->time ->method ('getTime ' )
368374 ->willReturn (1000 );
369375
376+ $ this ->db ->expects ($ this ->once ())
377+ ->method ('beginTransaction ' );
378+
379+ $ this ->db ->expects ($ this ->once ())
380+ ->method ('commit ' );
381+
382+ $ this ->db ->expects ($ this ->never ())
383+ ->method ('rollBack ' );
384+
385+ $ this ->tokenProvider ->expects ($ this ->never ())
386+ ->method ('invalidateToken ' );
387+
370388 $ this ->tokenProvider ->expects ($ this ->once ())
371389 ->method ('updateToken ' )
372390 ->with (
@@ -380,13 +398,14 @@ public function testRefreshTokenValidAppToken(): void {
380398 ->willReturn ('newEncryptedToken ' );
381399
382400 $ this ->accessTokenMapper ->expects ($ this ->once ())
383- ->method ('update ' )
401+ ->method ('rotateToken ' )
384402 ->with (
385- $ this ->callback (function (AccessToken $ token ) {
386- return $ token ->getHashedCode () === hash ('sha512 ' , 'random128 ' )
387- && $ token ->getEncryptedToken () === 'newEncryptedToken ' ;
388- })
389- );
403+ 21 ,
404+ 'validrefresh ' ,
405+ 'random128 ' ,
406+ 'newEncryptedToken ' ,
407+ false ,
408+ )->willReturn (1 );
390409
391410 $ expected = new JSONResponse ([
392411 'access_token ' => 'random72 ' ,
@@ -412,6 +431,7 @@ public function testRefreshTokenValidAppToken(): void {
412431
413432 public function testRefreshTokenValidAppTokenBasicAuth (): void {
414433 $ accessToken = new AccessToken ();
434+ $ accessToken ->setId (21 );
415435 $ accessToken ->setClientId (42 );
416436 $ accessToken ->setTokenId (1337 );
417437 $ accessToken ->setEncryptedToken ('encryptedToken ' );
@@ -463,6 +483,18 @@ public function testRefreshTokenValidAppTokenBasicAuth(): void {
463483 $ this ->time ->method ('getTime ' )
464484 ->willReturn (1000 );
465485
486+ $ this ->db ->expects ($ this ->once ())
487+ ->method ('beginTransaction ' );
488+
489+ $ this ->db ->expects ($ this ->once ())
490+ ->method ('commit ' );
491+
492+ $ this ->db ->expects ($ this ->never ())
493+ ->method ('rollBack ' );
494+
495+ $ this ->tokenProvider ->expects ($ this ->never ())
496+ ->method ('invalidateToken ' );
497+
466498 $ this ->tokenProvider ->expects ($ this ->once ())
467499 ->method ('updateToken ' )
468500 ->with (
@@ -476,13 +508,14 @@ public function testRefreshTokenValidAppTokenBasicAuth(): void {
476508 ->willReturn ('newEncryptedToken ' );
477509
478510 $ this ->accessTokenMapper ->expects ($ this ->once ())
479- ->method ('update ' )
511+ ->method ('rotateToken ' )
480512 ->with (
481- $ this ->callback (function (AccessToken $ token ) {
482- return $ token ->getHashedCode () === hash ('sha512 ' , 'random128 ' )
483- && $ token ->getEncryptedToken () === 'newEncryptedToken ' ;
484- })
485- );
513+ 21 ,
514+ 'validrefresh ' ,
515+ 'random128 ' ,
516+ 'newEncryptedToken ' ,
517+ false ,
518+ )->willReturn (1 );
486519
487520 $ expected = new JSONResponse ([
488521 'access_token ' => 'random72 ' ,
@@ -511,6 +544,7 @@ public function testRefreshTokenValidAppTokenBasicAuth(): void {
511544
512545 public function testRefreshTokenExpiredAppToken (): void {
513546 $ accessToken = new AccessToken ();
547+ $ accessToken ->setId (21 );
514548 $ accessToken ->setClientId (42 );
515549 $ accessToken ->setTokenId (1337 );
516550 $ accessToken ->setEncryptedToken ('encryptedToken ' );
@@ -562,6 +596,18 @@ public function testRefreshTokenExpiredAppToken(): void {
562596 $ this ->time ->method ('getTime ' )
563597 ->willReturn (1000 );
564598
599+ $ this ->db ->expects ($ this ->once ())
600+ ->method ('beginTransaction ' );
601+
602+ $ this ->db ->expects ($ this ->once ())
603+ ->method ('commit ' );
604+
605+ $ this ->db ->expects ($ this ->never ())
606+ ->method ('rollBack ' );
607+
608+ $ this ->tokenProvider ->expects ($ this ->never ())
609+ ->method ('invalidateToken ' );
610+
565611 $ this ->tokenProvider ->expects ($ this ->once ())
566612 ->method ('updateToken ' )
567613 ->with (
@@ -575,13 +621,14 @@ public function testRefreshTokenExpiredAppToken(): void {
575621 ->willReturn ('newEncryptedToken ' );
576622
577623 $ this ->accessTokenMapper ->expects ($ this ->once ())
578- ->method ('update ' )
624+ ->method ('rotateToken ' )
579625 ->with (
580- $ this ->callback (function (AccessToken $ token ) {
581- return $ token ->getHashedCode () === hash ('sha512 ' , 'random128 ' )
582- && $ token ->getEncryptedToken () === 'newEncryptedToken ' ;
583- })
584- );
626+ 21 ,
627+ 'validrefresh ' ,
628+ 'random128 ' ,
629+ 'newEncryptedToken ' ,
630+ false ,
631+ )->willReturn (1 );
585632
586633 $ expected = new JSONResponse ([
587634 'access_token ' => 'random72 ' ,
@@ -604,4 +651,89 @@ public function testRefreshTokenExpiredAppToken(): void {
604651
605652 $ this ->assertEquals ($ expected , $ this ->oauthApiController ->getToken ('refresh_token ' , null , 'validrefresh ' , 'clientId ' , 'clientSecret ' ));
606653 }
654+
655+ public function testRefreshTokenRedeemedConcurrently (): void {
656+ $ expected = new JSONResponse ([
657+ 'error ' => 'invalid_request ' ,
658+ ], Http::STATUS_BAD_REQUEST );
659+ $ expected ->throttle (['invalid_request ' => 'refresh_token_already_redeemed ' ]);
660+
661+ $ accessToken = new AccessToken ();
662+ $ accessToken ->setId (21 );
663+ $ accessToken ->setClientId (42 );
664+ $ accessToken ->setTokenId (1337 );
665+ $ accessToken ->setEncryptedToken ('encryptedToken ' );
666+
667+ $ this ->accessTokenMapper ->method ('getByCode ' )
668+ ->with ('validrefresh ' )
669+ ->willReturn ($ accessToken );
670+
671+ $ client = new Client ();
672+ $ client ->setClientIdentifier ('clientId ' );
673+ $ client ->setSecret (bin2hex ('hashedClientSecret ' ));
674+ $ this ->clientMapper ->method ('getByUid ' )
675+ ->with (42 )
676+ ->willReturn ($ client );
677+
678+ $ this ->crypto
679+ ->method ('decrypt ' )
680+ ->with ('encryptedToken ' )
681+ ->willReturn ('decryptedToken ' );
682+
683+ $ this ->crypto
684+ ->method ('calculateHMAC ' )
685+ ->with ('clientSecret ' )
686+ ->willReturn ('hashedClientSecret ' );
687+
688+ $ appToken = new PublicKeyToken ();
689+ $ appToken ->setUid ('userId ' );
690+ $ this ->tokenProvider ->method ('getTokenById ' )
691+ ->with (1337 )
692+ ->willReturn ($ appToken );
693+
694+ $ this ->secureRandom ->method ('generate ' )
695+ ->willReturnCallback (function ($ len ) {
696+ return 'random ' . $ len ;
697+ });
698+
699+ $ this ->tokenProvider ->expects ($ this ->never ())
700+ ->method ('rotate ' );
701+
702+ $ this ->time ->method ('getTime ' )
703+ ->willReturn (1000 );
704+
705+ $ this ->tokenProvider ->expects ($ this ->never ())
706+ ->method ('updateToken ' );
707+
708+ $ this ->crypto ->method ('encrypt ' )
709+ ->with ('random72 ' , 'random128 ' )
710+ ->willReturn ('newEncryptedToken ' );
711+
712+ $ this ->db ->expects ($ this ->once ())
713+ ->method ('beginTransaction ' );
714+
715+ $ this ->db ->expects ($ this ->never ())
716+ ->method ('commit ' );
717+
718+ $ this ->db ->expects ($ this ->once ())
719+ ->method ('rollBack ' );
720+
721+ $ this ->tokenProvider ->expects ($ this ->never ())
722+ ->method ('invalidateToken ' );
723+
724+ $ this ->accessTokenMapper ->expects ($ this ->once ())
725+ ->method ('rotateToken ' )
726+ ->with (
727+ 21 ,
728+ 'validrefresh ' ,
729+ 'random128 ' ,
730+ 'newEncryptedToken ' ,
731+ false ,
732+ )->willReturn (0 );
733+
734+ $ this ->throttler ->expects ($ this ->never ())
735+ ->method ('resetDelay ' );
736+
737+ $ this ->assertEquals ($ expected , $ this ->oauthApiController ->getToken ('refresh_token ' , null , 'validrefresh ' , 'clientId ' , 'clientSecret ' ));
738+ }
607739}
0 commit comments