100.00% covered (success)
@@ -829,237 +829,238 @@
617
618
619 $code = $this -> authorizationForm -> transformAuthorizationCode ( $request , $code ) ;
-
620
-
621
-
622 $authCode = $this -> tokenStorage -> createAuthCode ( $code ) ;
-
623 if ( is_null ( $authCode ) ) {
-
624
-
625
-
626 $this -> logger -> error ( "Saving the authorization code failed and returned false without raising an exception." ) ;
-
627 throw IndieAuthException :: create ( IndieAuthException :: INTERNAL_ERROR_REDIRECT , $request ) ;
-
628 }
-
629
-
630
-
631 return new Response ( 302 , [
-
632 'Location' => appendQueryParams ( $queryParams [ 'redirect_uri' ] , [
-
633 'code' => $authCode ,
-
634 'state' => $code [ 'state' ]
-
635 ] ) ,
-
636 'Cache-control' => 'no-cache'
-
637 ] ) ;
-
638 }
-
639
-
640
-
641
-
642
-
643
-
644
-
645
-
646
-
647
-
648 if ( is_null ( $clientIdResponse ) || is_null ( $clientIdEffectiveUrl ) || is_null ( $clientIdMf2 ) ) {
-
649 try {
-
650
-
651 list ( $clientIdResponse , $clientIdEffectiveUrl ) = call_user_func ( $this -> httpGetWithEffectiveUrl , $queryParams [ 'client_id' ] ) ;
-
652 $clientIdMf2 = Mf2 \ parse ( (string) $clientIdResponse -> getBody ( ) , $clientIdEffectiveUrl ) ;
-
653 } catch ( ClientExceptionInterface | RequestExceptionInterface | NetworkExceptionInterface $e ) {
-
654 $this -> logger -> error ( "Caught an HTTP exception while trying to fetch the client_id. Returning an error response." , [
-
655 'client_id' => $queryParams [ 'client_id' ] ,
-
656 'exception' => $e -> __toString ( )
-
657 ] ) ;
-
658
-
659
-
660
-
661 throw IndieAuthException :: create ( IndieAuthException :: INTERNAL_ERROR_REDIRECT , $request , $e ) ;
-
662 } catch ( Exception $e ) {
-
663 $this -> logger -> error ( "Caught an unknown exception while trying to fetch the client_id. Returning an error response." , [
-
664 'exception' => $e -> __toString ( )
-
665 ] ) ;
-
666
-
667 throw IndieAuthException :: create ( IndieAuthException :: INTERNAL_ERROR_REDIRECT , $request , $e ) ;
-
668 }
-
669 }
-
670
-
671
-
672 $clientHApps = M \ findMicroformatsByProperty ( M \ findMicroformatsByType ( $clientIdMf2 , 'h-app' ) , 'url' , $queryParams [ 'client_id' ] ) ;
-
673 $clientHApp = empty ( $clientHApps ) ? null : $clientHApps [ 0 ] ;
-
674
-
675
-
676 return $this -> authorizationForm -> showForm ( $request , $authenticationResult , $authenticationRedirect , $clientHApp )
-
677 -> withAddedHeader ( 'Cache-control' , 'no-cache' ) ;
-
678 }
-
679 }
-
680
-
681
-
682
-
683 $nonIndieAuthRequestResult = call_user_func ( $this -> handleNonIndieAuthRequest , $request ) ;
-
684 if ( $nonIndieAuthRequestResult instanceof ResponseInterface ) {
-
685 return $nonIndieAuthRequestResult ;
-
686 } else {
-
687
-
688
-
689 throw IndieAuthException :: create ( IndieAuthException :: INTERNAL_ERROR , $request ) ;
-
690 }
-
691 } catch ( IndieAuthException $e ) {
-
692
-
693 return $this -> handleException ( $e ) ;
-
694 } catch ( Exception $e ) {
-
695
-
696 $this -> logger -> error ( " Caught unknown exception: { $e } " ) ;
-
697 return $this -> handleException ( IndieAuthException :: create ( 0 , $request , $e ) ) ;
-
698 }
-
699 } ) ) ;
-
700 }
-
701
-
702
-
703
-
704
-
705
-
706
-
707
-
708
-
709
-
710
-
711
-
712
-
713
-
714
-
715
-
716
-
717
-
718
-
719
-
720 public function handleTokenEndpointRequest ( ServerRequestInterface $request ) : ResponseInterface {
-
721 if ( isIndieAuthAuthorizationCodeRedeemingRequest ( $request ) ) {
-
722 $this -> logger -> info ( 'Handling a request to redeem an authorization code for profile information.' ) ;
-
723
-
724 $bodyParams = $request -> getParsedBody ( ) ;
-
725
-
726 if ( ! isset ( $bodyParams [ 'code' ] ) ) {
-
727 $this -> logger -> warning ( 'The exchange request was missing the code parameter. Returning an error response.' ) ;
-
728 return new Response ( 400 , [ 'content-type' => 'application/json' ] , json_encode ( [
-
729 'error' => 'invalid_request' ,
-
730 'error_description' => 'The code parameter was missing.'
-
731 ] ) ) ;
-
732 }
-
733
-
734
-
735
-
736
-
737
-
738 try {
-
739
-
740
-
741 $tokenData = $this -> tokenStorage -> exchangeAuthCodeForAccessToken ( $bodyParams [ 'code' ] , function ( array $authCode ) use ( $request , $bodyParams ) {
-
742
-
743 $requiredParameters = ( $this -> requirePkce or ! empty ( $authCode [ 'code_challenge' ] ) ) ? [ 'client_id' , 'redirect_uri' , 'code_verifier' ] : [ 'client_id' , 'redirect_uri' ] ;
-
744 $missingRequiredParameters = array_filter ( $requiredParameters , function ( $p ) use ( $bodyParams ) {
-
745 return ! array_key_exists ( $p , $bodyParams ) || empty ( $bodyParams [ $p ] ) ;
-
746 } ) ;
-
747 if ( ! empty ( $missingRequiredParameters ) ) {
-
748 $this -> logger -> warning ( 'The exchange request was missing required parameters. Returning an error response.' , [ 'missing' => $missingRequiredParameters ] ) ;
-
749 throw IndieAuthException :: create ( IndieAuthException :: INVALID_REQUEST , $request ) ;
-
750 }
-
751
-
752
-
753 if ( $authCode [ 'client_id' ] !== $bodyParams [ 'client_id' ]
-
754 || $authCode [ 'redirect_uri' ] !== $bodyParams [ 'redirect_uri' ] ) {
-
755 $this -> logger -> error ( "The provided client_id and/or redirect_uri did not match those stored in the token." ) ;
-
756 throw IndieAuthException :: create ( IndieAuthException :: INVALID_GRANT , $request ) ;
-
757 }
-
758
-
759
-
760
-
761 if ( ! empty ( $bodyParams [ 'code_verifier' ] ) && empty ( $authCode [ 'code_challenge' ] ) ) {
-
762 $this -> logger -> error ( "A code_verifier was provided when trying to exchange an auth code requested without a code_challenge." ) ;
-
763 throw IndieAuthException :: create ( IndieAuthException :: INVALID_GRANT , $request ) ;
-
764 }
-
765
-
766 if ( $this -> requirePkce or ! empty ( $authCode [ 'code_challenge' ] ) ) {
-
767
-
768
-
769 if ( ! hash_equals ( $authCode [ 'code_challenge' ] , generatePKCECodeChallenge ( $bodyParams [ 'code_verifier' ] ) ) ) {
-
770 $this -> logger -> error ( "The provided code_verifier did not hash to the stored code_challenge" ) ;
-
771 throw IndieAuthException :: create ( IndieAuthException :: INVALID_GRANT , $request ) ;
-
772 }
-
773 }
-
774
-
775
-
776 if ( empty ( $authCode [ 'scope' ] ) ) {
-
777 $this -> logger -> error ( "An exchange request for a token with an empty scope was sent to the token endpoint." ) ;
-
778 throw IndieAuthException :: create ( IndieAuthException :: INVALID_GRANT , $request ) ;
-
779 }
-
780 } ) ;
-
781 } catch ( IndieAuthException $e ) {
-
782
-
783 return new Response ( 400 , [ 'content-type' => 'application/json' ] , json_encode ( [
-
784 'error' => $e -> getInfo ( ) [ 'error' ] ,
-
785 'error_description' => $e -> getMessage ( )
-
786 ] ) ) ;
-
787 }
-
788
-
789 if ( is_null ( $tokenData ) ) {
-
790 $this -> logger -> error ( 'Attempting to exchange an auth code for a token resulted in null.' , $bodyParams ) ;
-
791 return new Response ( 400 , [ 'content-type' => 'application/json' ] , json_encode ( [
-
792 'error' => 'invalid_grant' ,
-
793 'error_description' => 'The provided credentials were not valid.'
-
794 ] ) ) ;
-
795 }
-
796
-
797
-
798
-
799
-
800 return new Response ( 200 , [
-
801 'content-type' => 'application/json' ,
-
802 'cache-control' => 'no-store' ,
-
803 ] , json_encode ( array_merge ( [
-
804
-
805 'token_type' => 'Bearer'
-
806 ] , array_filter ( $tokenData , function ( string $k ) {
-
807
-
808
-
809 return ! in_array ( $k , [ 'code_challenge' , 'code_challenge_method' ] ) ;
-
810 } , ARRAY_FILTER_USE_KEY ) ) ) ) ;
-
811 }
-
812
-
813 return new Response ( 400 , [ 'content-type' => 'application/json' ] , json_encode ( [
-
814 'error' => 'invalid_request' ,
-
815 'error_description' => 'Request to token endpoint was not a valid code exchange request.'
-
816 ] ) ) ;
-
817 }
-
818
-
819
-
820
-
821
-
822
-
823
-
824 protected function handleException ( IndieAuthException $exception ) : ResponseInterface {
-
825 $exceptionData = $exception -> getInfo ( ) ;
-
826
-
827 if ( $exceptionData [ 'statusCode' ] == 302 ) {
-
828
-
829 $redirectQueryParams = [
-
830 'error' => $exceptionData [ 'error' ] ?? 'invalid_request' ,
-
831 'error_description' => (string) $exception
-
832 ] ;
-
833
-
834
-
835 if ( $exception -> getCode ( ) !== IndieAuthException :: INVALID_STATE ) {
-
836 $redirectQueryParams [ 'state' ] = $exception -> getRequest ( ) -> getQueryParams ( ) [ 'state' ] ;
-
837 }
-
838
-
839 return new Response ( $exceptionData [ 'statusCode' ] , [
-
840 'Location' => appendQueryParams ( (string) $exception -> getRequest ( ) -> getQueryParams ( ) [ 'redirect_uri' ] , $redirectQueryParams )
-
841 ] ) ;
-
842 } else {
-
843
-
844 return new Response ( $exception -> getStatusCode ( ) , [ 'content-type' => 'text/html' ] , renderTemplate ( $this -> exceptionTemplatePath , [
-
845 'request' => $exception -> getRequest ( ) ,
-
846 'exception' => $exception
-
847 ] ) ) ;
-
848 }
-
849 }
-
850 }
+
620 $this -> logger -> info ( "Creating an authorization code:" , [ 'data' => $code ] ) ;
+
621
+
622
+
623 $authCode = $this -> tokenStorage -> createAuthCode ( $code ) ;
+
624 if ( is_null ( $authCode ) ) {
+
625
+
626
+
627 $this -> logger -> error ( "Saving the authorization code failed and returned false without raising an exception." ) ;
+
628 throw IndieAuthException :: create ( IndieAuthException :: INTERNAL_ERROR_REDIRECT , $request ) ;
+
629 }
+
630
+
631
+
632 return new Response ( 302 , [
+
633 'Location' => appendQueryParams ( $queryParams [ 'redirect_uri' ] , [
+
634 'code' => $authCode ,
+
635 'state' => $code [ 'state' ]
+
636 ] ) ,
+
637 'Cache-control' => 'no-cache'
+
638 ] ) ;
+
639 }
+
640
+
641
+
642
+
643
+
644
+
645
+
646
+
647
+
648
+
649 if ( is_null ( $clientIdResponse ) || is_null ( $clientIdEffectiveUrl ) || is_null ( $clientIdMf2 ) ) {
+
650 try {
+
651
+
652 list ( $clientIdResponse , $clientIdEffectiveUrl ) = call_user_func ( $this -> httpGetWithEffectiveUrl , $queryParams [ 'client_id' ] ) ;
+
653 $clientIdMf2 = Mf2 \ parse ( (string) $clientIdResponse -> getBody ( ) , $clientIdEffectiveUrl ) ;
+
654 } catch ( ClientExceptionInterface | RequestExceptionInterface | NetworkExceptionInterface $e ) {
+
655 $this -> logger -> error ( "Caught an HTTP exception while trying to fetch the client_id. Returning an error response." , [
+
656 'client_id' => $queryParams [ 'client_id' ] ,
+
657 'exception' => $e -> __toString ( )
+
658 ] ) ;
+
659
+
660
+
661
+
662 throw IndieAuthException :: create ( IndieAuthException :: INTERNAL_ERROR_REDIRECT , $request , $e ) ;
+
663 } catch ( Exception $e ) {
+
664 $this -> logger -> error ( "Caught an unknown exception while trying to fetch the client_id. Returning an error response." , [
+
665 'exception' => $e -> __toString ( )
+
666 ] ) ;
+
667
+
668 throw IndieAuthException :: create ( IndieAuthException :: INTERNAL_ERROR_REDIRECT , $request , $e ) ;
+
669 }
+
670 }
+
671
+
672
+
673 $clientHApps = M \ findMicroformatsByProperty ( M \ findMicroformatsByType ( $clientIdMf2 , 'h-app' ) , 'url' , $queryParams [ 'client_id' ] ) ;
+
674 $clientHApp = empty ( $clientHApps ) ? null : $clientHApps [ 0 ] ;
+
675
+
676
+
677 return $this -> authorizationForm -> showForm ( $request , $authenticationResult , $authenticationRedirect , $clientHApp )
+
678 -> withAddedHeader ( 'Cache-control' , 'no-cache' ) ;
+
679 }
+
680 }
+
681
+
682
+
683
+
684 $nonIndieAuthRequestResult = call_user_func ( $this -> handleNonIndieAuthRequest , $request ) ;
+
685 if ( $nonIndieAuthRequestResult instanceof ResponseInterface ) {
+
686 return $nonIndieAuthRequestResult ;
+
687 } else {
+
688
+
689
+
690 throw IndieAuthException :: create ( IndieAuthException :: INTERNAL_ERROR , $request ) ;
+
691 }
+
692 } catch ( IndieAuthException $e ) {
+
693
+
694 return $this -> handleException ( $e ) ;
+
695 } catch ( Exception $e ) {
+
696
+
697 $this -> logger -> error ( " Caught unknown exception: { $e } " ) ;
+
698 return $this -> handleException ( IndieAuthException :: create ( 0 , $request , $e ) ) ;
+
699 }
+
700 } ) ) ;
+
701 }
+
702
+
703
+
704
+
705
+
706
+
707
+
708
+
709
+
710
+
711
+
712
+
713
+
714
+
715
+
716
+
717
+
718
+
719
+
720
+
721 public function handleTokenEndpointRequest ( ServerRequestInterface $request ) : ResponseInterface {
+
722 if ( isIndieAuthAuthorizationCodeRedeemingRequest ( $request ) ) {
+
723 $this -> logger -> info ( 'Handling a request to redeem an authorization code for an access token.' ) ;
+
724
+
725 $bodyParams = $request -> getParsedBody ( ) ;
+
726
+
727 if ( ! isset ( $bodyParams [ 'code' ] ) ) {
+
728 $this -> logger -> warning ( 'The exchange request was missing the code parameter. Returning an error response.' ) ;
+
729 return new Response ( 400 , [ 'content-type' => 'application/json' ] , json_encode ( [
+
730 'error' => 'invalid_request' ,
+
731 'error_description' => 'The code parameter was missing.'
+
732 ] ) ) ;
+
733 }
+
734
+
735
+
736
+
737
+
738
+
739 try {
+
740
+
741
+
742 $tokenData = $this -> tokenStorage -> exchangeAuthCodeForAccessToken ( $bodyParams [ 'code' ] , function ( array $authCode ) use ( $request , $bodyParams ) {
+
743
+
744 $requiredParameters = ( $this -> requirePkce or ! empty ( $authCode [ 'code_challenge' ] ) ) ? [ 'client_id' , 'redirect_uri' , 'code_verifier' ] : [ 'client_id' , 'redirect_uri' ] ;
+
745 $missingRequiredParameters = array_filter ( $requiredParameters , function ( $p ) use ( $bodyParams ) {
+
746 return ! array_key_exists ( $p , $bodyParams ) || empty ( $bodyParams [ $p ] ) ;
+
747 } ) ;
+
748 if ( ! empty ( $missingRequiredParameters ) ) {
+
749 $this -> logger -> warning ( 'The exchange request was missing required parameters. Returning an error response.' , [ 'missing' => $missingRequiredParameters ] ) ;
+
750 throw IndieAuthException :: create ( IndieAuthException :: INVALID_REQUEST , $request ) ;
+
751 }
+
752
+
753
+
754 if ( $authCode [ 'client_id' ] !== $bodyParams [ 'client_id' ]
+
755 || $authCode [ 'redirect_uri' ] !== $bodyParams [ 'redirect_uri' ] ) {
+
756 $this -> logger -> error ( "The provided client_id and/or redirect_uri did not match those stored in the token." ) ;
+
757 throw IndieAuthException :: create ( IndieAuthException :: INVALID_GRANT , $request ) ;
+
758 }
+
759
+
760
+
761
+
762 if ( ! empty ( $bodyParams [ 'code_verifier' ] ) && empty ( $authCode [ 'code_challenge' ] ) ) {
+
763 $this -> logger -> error ( "A code_verifier was provided when trying to exchange an auth code requested without a code_challenge." ) ;
+
764 throw IndieAuthException :: create ( IndieAuthException :: INVALID_GRANT , $request ) ;
+
765 }
+
766
+
767 if ( $this -> requirePkce or ! empty ( $authCode [ 'code_challenge' ] ) ) {
+
768
+
769
+
770 if ( ! hash_equals ( $authCode [ 'code_challenge' ] , generatePKCECodeChallenge ( $bodyParams [ 'code_verifier' ] ) ) ) {
+
771 $this -> logger -> error ( "The provided code_verifier did not hash to the stored code_challenge" ) ;
+
772 throw IndieAuthException :: create ( IndieAuthException :: INVALID_GRANT , $request ) ;
+
773 }
+
774 }
+
775
+
776
+
777 if ( empty ( $authCode [ 'scope' ] ) ) {
+
778 $this -> logger -> error ( "An exchange request for a token with an empty scope was sent to the token endpoint." ) ;
+
779 throw IndieAuthException :: create ( IndieAuthException :: INVALID_GRANT , $request ) ;
+
780 }
+
781 } ) ;
+
782 } catch ( IndieAuthException $e ) {
+
783
+
784 return new Response ( 400 , [ 'content-type' => 'application/json' ] , json_encode ( [
+
785 'error' => $e -> getInfo ( ) [ 'error' ] ,
+
786 'error_description' => $e -> getMessage ( )
+
787 ] ) ) ;
+
788 }
+
789
+
790 if ( is_null ( $tokenData ) ) {
+
791 $this -> logger -> error ( 'Attempting to exchange an auth code for a token resulted in null.' , $bodyParams ) ;
+
792 return new Response ( 400 , [ 'content-type' => 'application/json' ] , json_encode ( [
+
793 'error' => 'invalid_grant' ,
+
794 'error_description' => 'The provided credentials were not valid.'
+
795 ] ) ) ;
+
796 }
+
797
+
798
+
799
+
800
+
801 return new Response ( 200 , [
+
802 'content-type' => 'application/json' ,
+
803 'cache-control' => 'no-store' ,
+
804 ] , json_encode ( array_merge ( [
+
805
+
806 'token_type' => 'Bearer'
+
807 ] , array_filter ( $tokenData , function ( string $k ) {
+
808
+
809
+
810 return ! in_array ( $k , [ 'code_challenge' , 'code_challenge_method' ] ) ;
+
811 } , ARRAY_FILTER_USE_KEY ) ) ) ) ;
+
812 }
+
813
+
814 return new Response ( 400 , [ 'content-type' => 'application/json' ] , json_encode ( [
+
815 'error' => 'invalid_request' ,
+
816 'error_description' => 'Request to token endpoint was not a valid code exchange request.'
+
817 ] ) ) ;
+
818 }
+
819
+
820
+
821
+
822
+
823
+
824
+
825 protected function handleException ( IndieAuthException $exception ) : ResponseInterface {
+
826 $exceptionData = $exception -> getInfo ( ) ;
+
827
+
828 if ( $exceptionData [ 'statusCode' ] == 302 ) {
+
829
+
830 $redirectQueryParams = [
+
831 'error' => $exceptionData [ 'error' ] ?? 'invalid_request' ,
+
832 'error_description' => (string) $exception
+
833 ] ;
+
834
+
835
+
836 if ( $exception -> getCode ( ) !== IndieAuthException :: INVALID_STATE ) {
+
837 $redirectQueryParams [ 'state' ] = $exception -> getRequest ( ) -> getQueryParams ( ) [ 'state' ] ;
+
838 }
+
839
+
840 return new Response ( $exceptionData [ 'statusCode' ] , [
+
841 'Location' => appendQueryParams ( (string) $exception -> getRequest ( ) -> getQueryParams ( ) [ 'redirect_uri' ] , $redirectQueryParams )
+
842 ] ) ;
+
843 } else {
+
844
+
845 return new Response ( $exception -> getStatusCode ( ) , [ 'content-type' => 'text/html' ] , renderTemplate ( $this -> exceptionTemplatePath , [
+
846 'request' => $exception -> getRequest ( ) ,
+
847 'exception' => $exception
+
848 ] ) ) ;
+
849 }
+
850 }
+
851 }
@@ -1070,7 +1071,7 @@
Legend
Executed Not Executed Dead Code
- Generated by php-code-coverage 9.2.6 using PHP 7.4.19 with Xdebug 3.0.4 and PHPUnit 9.5.5 at Fri Jun 18 14:09:49 UTC 2021.
+ Generated by php-code-coverage 9.2.6 using PHP 7.4.19 with Xdebug 3.0.4 and PHPUnit 9.5.5 at Fri Jun 18 14:43:22 UTC 2021.
diff --git a/docs/coverage/Storage/FilesystemJsonStorage.php.html b/docs/coverage/Storage/FilesystemJsonStorage.php.html
index eedc1e0..e00ae36 100644
--- a/docs/coverage/Storage/FilesystemJsonStorage.php.html
+++ b/docs/coverage/Storage/FilesystemJsonStorage.php.html
@@ -52,23 +52,23 @@