55use api:: auth:: { AuthResponse , Authorizer } ;
66use api:: error:: VssError ;
77use async_trait:: async_trait;
8- use jsonwebtoken:: { decode, Algorithm , DecodingKey , Validation } ;
9- use serde:: { Deserialize , Serialize } ;
8+ use base64:: engine:: general_purpose:: { STANDARD , URL_SAFE_NO_PAD } ;
9+ use base64:: Engine ;
10+ use rsa:: sha2:: { Digest , Sha256 } ;
11+ use rsa:: { pkcs8:: DecodePublicKey , RsaPublicKey } ;
12+ use serde:: Deserialize ;
1013use std:: collections:: HashMap ;
1114
1215/// A JWT based authorizer, only allows requests with verified 'JsonWebToken' signed by the given
1316/// issuer key.
1417///
1518/// Refer: https://datatracker.ietf.org/doc/html/rfc7519
1619pub struct JWTAuthorizer {
17- jwt_issuer_key : DecodingKey ,
20+ jwt_issuer_key : RsaPublicKey ,
1821}
1922
2023/// A set of Claims claimed by 'JsonWebToken'
2124///
2225/// Refer: https://datatracker.ietf.org/doc/html/rfc7519#section-4
23- #[ derive( Serialize , Deserialize , Debug ) ]
26+ #[ derive( Deserialize , Debug ) ]
2427pub ( crate ) struct Claims {
2528 /// The "sub" (subject) claim identifies the principal that is the subject of the JWT.
2629 /// The claims in a JWT are statements about the subject. This can be used as user identifier.
@@ -31,10 +34,22 @@ pub(crate) struct Claims {
3134
3235const BEARER_PREFIX : & str = "Bearer " ;
3336
37+ fn parse_public_key_pem ( pem : & str ) -> Result < RsaPublicKey , String > {
38+ let body = pem
39+ . trim ( )
40+ . strip_prefix ( "-----BEGIN PUBLIC KEY-----" )
41+ . ok_or ( String :: from ( "Prefix not found" ) ) ?
42+ . strip_suffix ( "-----END PUBLIC KEY-----" )
43+ . ok_or ( String :: from ( "Suffix not found" ) ) ?;
44+ let body: String = body. lines ( ) . map ( |line| line. trim ( ) ) . collect ( ) ;
45+ let body = STANDARD . decode ( body) . map_err ( |_| String :: from ( "Base64 decode failed" ) ) ?;
46+ RsaPublicKey :: from_public_key_der ( & body) . map_err ( |_| String :: from ( "DER decode failed" ) )
47+ }
48+
3449impl JWTAuthorizer {
3550 /// Creates a new instance of [`JWTAuthorizer`], fails on failure to parse the PEM formatted RSA public key
3651 pub async fn new ( rsa_pem : & str ) -> Result < Self , String > {
37- let jwt_issuer_key = DecodingKey :: from_rsa_pem ( rsa_pem. as_bytes ( ) )
52+ let jwt_issuer_key = parse_public_key_pem ( rsa_pem)
3853 . map_err ( |e| format ! ( "Failed to parse the PEM formatted RSA public key: {}" , e) ) ?;
3954 Ok ( Self { jwt_issuer_key } )
4055 }
@@ -53,10 +68,41 @@ impl Authorizer for JWTAuthorizer {
5368 . strip_prefix ( BEARER_PREFIX )
5469 . ok_or ( VssError :: AuthError ( "Invalid token format." . to_string ( ) ) ) ?;
5570
56- let claims =
57- decode :: < Claims > ( token, & self . jwt_issuer_key , & Validation :: new ( Algorithm :: RS256 ) )
58- . map_err ( |e| VssError :: AuthError ( format ! ( "Authentication failure. {}" , e) ) ) ?
59- . claims ;
71+ let mut iter = token. split ( '.' ) ;
72+ let [ header_base64, claims_base64, signature_base64] =
73+ match [ iter. next ( ) , iter. next ( ) , iter. next ( ) , iter. next ( ) ] {
74+ [ Some ( h) , Some ( c) , Some ( s) , None ] => [ h, c, s] ,
75+ _ => {
76+ return Err ( VssError :: AuthError ( String :: from (
77+ "Token does not have three parts" ,
78+ ) ) )
79+ } ,
80+ } ;
81+
82+ let header_bytes = URL_SAFE_NO_PAD
83+ . decode ( header_base64)
84+ . map_err ( |_| VssError :: AuthError ( String :: from ( "Header base64 decode failed" ) ) ) ?;
85+ let header: serde_json:: Value = serde_json:: from_slice ( & header_bytes)
86+ . map_err ( |_| VssError :: AuthError ( String :: from ( "Header json decode failed" ) ) ) ?;
87+ match header[ "alg" ] {
88+ serde_json:: Value :: String ( ref alg) if alg == "RS256" => ( ) ,
89+ _ => return Err ( VssError :: AuthError ( String :: from ( "alg: RS256 not found in header" ) ) ) ,
90+ }
91+
92+ let ( message, _) = token. rsplit_once ( '.' ) . expect ( "There are two periods in the token" ) ;
93+ let signature = URL_SAFE_NO_PAD
94+ . decode ( signature_base64)
95+ . map_err ( |_| VssError :: AuthError ( String :: from ( "Signature base64 decode failed" ) ) ) ?;
96+ let digest = Sha256 :: digest ( message. as_bytes ( ) ) ;
97+ self . jwt_issuer_key
98+ . verify ( rsa:: pkcs1v15:: Pkcs1v15Sign :: new :: < Sha256 > ( ) , & digest, & signature)
99+ . map_err ( |_| VssError :: AuthError ( String :: from ( "RSA verification failed" ) ) ) ?;
100+
101+ let claims_json = URL_SAFE_NO_PAD
102+ . decode ( claims_base64)
103+ . map_err ( |_| VssError :: AuthError ( String :: from ( "Claims base64 decode failed" ) ) ) ?;
104+ let claims: Claims = serde_json:: from_slice ( & claims_json)
105+ . map_err ( |_| VssError :: AuthError ( String :: from ( "Claims json decode failed" ) ) ) ?;
60106
61107 Ok ( AuthResponse { user_token : claims. sub } )
62108 }
0 commit comments