Skip to content

Commit

Permalink
fix(rpc): make exp claim optional (paradigmxyz#1601)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rjected authored Mar 1, 2023
1 parent 42e3f56 commit ad0ce8c
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 10 deletions.
6 changes: 3 additions & 3 deletions crates/rpc/rpc/src/layers/auth_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ mod tests {
}

async fn valid_jwt() {
let claims = Claims { iat: to_u64(SystemTime::now()), exp: 10000000000 };
let claims = Claims { iat: to_u64(SystemTime::now()), exp: Some(10000000000) };
let secret = JwtSecret::from_hex(SECRET).unwrap(); // Same secret as the server
let jwt = secret.encode(&claims).unwrap();
let (status, _) = send_request(Some(jwt)).await;
Expand All @@ -209,7 +209,7 @@ mod tests {
// This secret is different from the server. This will generate a
// different signature
let secret = JwtSecret::random();
let claims = Claims { iat: to_u64(SystemTime::now()), exp: 10000000000 };
let claims = Claims { iat: to_u64(SystemTime::now()), exp: Some(10000000000) };
let jwt = secret.encode(&claims).unwrap();

let (status, body) = send_request(Some(jwt)).await;
Expand All @@ -222,7 +222,7 @@ mod tests {
let secret = JwtSecret::from_hex(SECRET).unwrap(); // Same secret as the server

let iat = to_u64(SystemTime::now()) + 1000;
let claims = Claims { iat, exp: 10000000000 };
let claims = Claims { iat, exp: Some(10000000000) };
let jwt = secret.encode(&claims).unwrap();

let (status, body) = send_request(Some(jwt)).await;
Expand Down
28 changes: 21 additions & 7 deletions crates/rpc/rpc/src/layers/jwt_secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ impl JwtSecret {
///
/// See also: [JWT Claims - Engine API specs](https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md#jwt-claims)
pub fn validate(&self, jwt: String) -> Result<(), JwtError> {
let validation = Validation::new(JWT_SIGNATURE_ALGO);
let mut validation = Validation::new(JWT_SIGNATURE_ALGO);
// ensure that the JWT has an `iat` claim
validation.set_required_spec_claims(&["iat"]);
let bytes = &self.0;

match decode::<Claims>(&jwt, &DecodingKey::from_secret(bytes), &validation) {
Expand Down Expand Up @@ -165,7 +167,7 @@ pub(crate) struct Claims {
/// - [`RFC-7519 - Spec`](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6)
/// - [`RFC-7519 - Notations`](https://www.rfc-editor.org/rfc/rfc7519#section-2)
pub(crate) iat: u64,
pub(crate) exp: u64,
pub(crate) exp: Option<u64>,
}

impl Claims {
Expand Down Expand Up @@ -239,7 +241,7 @@ mod tests {
#[test]
fn validation_ok() {
let secret = JwtSecret::random();
let claims = Claims { iat: to_u64(SystemTime::now()), exp: 10000000000 };
let claims = Claims { iat: to_u64(SystemTime::now()), exp: Some(10000000000) };
let jwt: String = secret.encode(&claims).unwrap();

let result = secret.validate(jwt);
Expand All @@ -254,7 +256,7 @@ mod tests {
// Check past 'iat' claim more than 60 secs
let offset = Duration::from_secs(JWT_MAX_IAT_DIFF.as_secs() + 1);
let out_of_window_time = SystemTime::now().checked_sub(offset).unwrap();
let claims = Claims { iat: to_u64(out_of_window_time), exp: 10000000000 };
let claims = Claims { iat: to_u64(out_of_window_time), exp: Some(10000000000) };
let jwt: String = secret.encode(&claims).unwrap();

let result = secret.validate(jwt);
Expand All @@ -264,7 +266,7 @@ mod tests {
// Check future 'iat' claim more than 60 secs
let offset = Duration::from_secs(JWT_MAX_IAT_DIFF.as_secs() + 1);
let out_of_window_time = SystemTime::now().checked_add(offset).unwrap();
let claims = Claims { iat: to_u64(out_of_window_time), exp: 10000000000 };
let claims = Claims { iat: to_u64(out_of_window_time), exp: Some(10000000000) };
let jwt: String = secret.encode(&claims).unwrap();

let result = secret.validate(jwt);
Expand All @@ -275,7 +277,7 @@ mod tests {
#[test]
fn validation_error_wrong_signature() {
let secret_1 = JwtSecret::random();
let claims = Claims { iat: to_u64(SystemTime::now()), exp: 10000000000 };
let claims = Claims { iat: to_u64(SystemTime::now()), exp: Some(10000000000) };
let jwt: String = secret_1.encode(&claims).unwrap();

// A different secret will generate a different signature.
Expand All @@ -292,13 +294,25 @@ mod tests {
let key = EncodingKey::from_secret(bytes);
let unsupported_algo = Header::new(Algorithm::HS384);

let claims = Claims { iat: to_u64(SystemTime::now()), exp: 10000000000 };
let claims = Claims { iat: to_u64(SystemTime::now()), exp: Some(10000000000) };
let jwt: String = encode(&unsupported_algo, &claims, &key).unwrap();
let result = secret.validate(jwt);

assert!(matches!(result, Err(JwtError::UnsupportedSignatureAlgorithm)));
}

#[test]
fn valid_without_exp_claim() {
let secret = JwtSecret::random();

let claims = Claims { iat: to_u64(SystemTime::now()), exp: None };
let jwt: String = secret.encode(&claims).unwrap();

let result = secret.validate(jwt);

assert!(matches!(result, Ok(())));
}

#[test]
fn ephemeral_secret_created() {
let fpath: &Path = Path::new("secret0.hex");
Expand Down

0 comments on commit ad0ce8c

Please sign in to comment.