Skip to content

Commit

Permalink
feat: auth unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
ralvescosta committed Apr 26, 2024
1 parent 0b66793 commit 85d5bf7
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 6 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Ruskit

:warning::construction: **Work In Progress** :construction::warning:

[![ci](https://github.com/ralvescosta/ruskit/actions/workflows/ci.yml/badge.svg)](https://github.com/ralvescosta/ruskit/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/ralvescosta/ruskit/branch/main/graph/badge.svg?token=6EAILKZFDO)](https://codecov.io/gh/ralvescosta/ruskit)

[![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ralvescosta/ruskit/blob/main/LICENSE)
Expand Down
6 changes: 5 additions & 1 deletion auth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ thiserror = { workspace = true }
tokio = { workspace = true, features = ["sync"] }
reqwest = { version = "0.12.3", features = ["json"] }
moka = { version = "0.12.7", features = ["future"] }
jsonwebtoken = { version = "9.3.0" }
jsonwebtoken = { version = "9.3.0" }

[dev-dependencies]
openssl = "0.10"
base64 = "0.13"
206 changes: 203 additions & 3 deletions auth/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ pub trait JwtManager: Send + Sync {
};

let Some(jwk) = jwks.find(&kid) else {
error!("wasn't possible to find the same token kid into jwks");
error!("wasn't possible to find the some token kid into jwks");
return Err(AuthError::InvalidToken(
"wasn't possible to find the same token kid into jwks".into(),
"wasn't possible to find the some token kid into jwks".into(),
));
};

Expand Down Expand Up @@ -68,7 +68,6 @@ pub trait JwtManager: Send + Sync {

let mut validation = Validation::new(alg);

//Validation::SubjectPresent
validation.set_audience(&[aud]);
validation.set_issuer(&[iss]);
validation.validate_exp = true;
Expand All @@ -82,3 +81,204 @@ pub trait JwtManager: Send + Sync {
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use jsonwebtoken::{encode, EncodingKey, Header};
use openssl::rsa::Rsa;
use serde::{Deserialize, Serialize};
use serde_json::json;

#[derive(Debug, Serialize, Deserialize)]
struct MockedClaims {
sub: String,
company: String,
exp: usize,
}

impl MockedClaims {
pub fn new() -> Self {
Self {
sub: "1234567890".to_owned(),
company: "ACME".to_owned(),
exp: 10000000000,
}
}
}

struct MyJwtManager;
#[async_trait]
impl JwtManager for MyJwtManager {
async fn verify(&self, _ctx: &Context, _token: &str) -> Result<TokenClaims, AuthError> {
todo!()
}
}

struct SetupTests {
pub manager: Box<dyn JwtManager>,
pub jwk_set: JwkSet,
pub claims: MockedClaims,
pub token: String,
}

impl SetupTests {
pub fn new(without_kid: bool, wrong_algorithm: bool) -> Self {
let claims = MockedClaims::new();

let rsa = Rsa::generate(2048).unwrap();
let private_key_pem = rsa.private_key_to_pem().unwrap();
let _public_key_pem = rsa.public_key_to_pem().unwrap();

let n = base64::encode_config(rsa.n().to_vec(), base64::URL_SAFE_NO_PAD);
let e = base64::encode_config(rsa.e().to_vec(), base64::URL_SAFE_NO_PAD);

// Construct the JWK
let serialized = json!({
"keys": [{
"kty": "RSA",
"n": n,
"e": e,
"use": "sig",
"alg": "RS256",
"kid": "key1"
}]
});

let jwk_set: JwkSet = serde_json::from_value(serialized).unwrap();

let encoding_key = EncodingKey::from_rsa_pem(&private_key_pem).unwrap();
let token = encode(
&Header {
typ: Some("JWT".into()),
alg: Self::alg(wrong_algorithm),
cty: None,
jku: None,
jwk: Some(jwk_set.keys[0].clone()),
kid: Self::kid(without_kid),
x5u: None,
x5c: None,
x5t: None,
x5t_s256: None,
},
&claims,
&encoding_key,
)
.unwrap();

let manager = Box::new(MyJwtManager);

Self {
manager,
jwk_set,
claims,
token,
}
}

fn kid(without: bool) -> Option<String> {
if without {
return None;
}

return Some("key1".into());
}

fn alg(wrong: bool) -> jsonwebtoken::Algorithm {
if wrong {
return jsonwebtoken::Algorithm::RS512;
}

return jsonwebtoken::Algorithm::RS256;
}
}

#[test]
fn test_decode_token() {
let sut = SetupTests::new(false, false);

let aud = "aud";
let iss = "iss";

let token_data = sut.manager.decode_token(&sut.token, &sut.jwk_set, aud, iss);
assert!(token_data.is_ok());
let token_data = token_data.unwrap();

let sub = token_data.claims.get("sub");
assert!(sub.is_some());
let sub = sub.unwrap().as_str().unwrap().to_string();

let company = token_data.claims.get("company");
assert!(company.is_some());
let company = company.unwrap().as_str().unwrap().to_string();

let exp = token_data.claims.get("exp");
assert!(exp.is_some());
let exp = exp.unwrap().as_i64().unwrap() as usize;

assert_eq!(sub, sut.claims.sub);
assert_eq!(company, sut.claims.company);
assert_eq!(exp, sut.claims.exp);
}

#[test]
fn test_decode_token_with_invalid_token() {
let sut = SetupTests::new(false, false);

let token_data =
sut.manager
.decode_token("invalid token", &sut.jwk_set, "aud".into(), "iss".into());

assert!(token_data.is_err());
assert_eq!(
token_data.unwrap_err(),
AuthError::InvalidToken("failed to decoded token header".into())
);
}

#[test]
fn test_decode_token_with_invalid_header() {
let token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.";
let sut = SetupTests::new(false, false);

let token_data = sut
.manager
.decode_token(token, &sut.jwk_set, "aud".into(), "iss".into());

assert!(token_data.is_err());
assert_eq!(
token_data.unwrap_err(),
AuthError::InvalidToken("failed to decoded token header".into())
);
}

#[test]
fn test_decode_token_with_invalid_kid() {
let sut = SetupTests::new(true, false);

let token_data =
sut.manager
.decode_token(&sut.token, &sut.jwk_set, "aud".into(), "iss".into());

assert!(token_data.is_err());
assert_eq!(
token_data.unwrap_err(),
AuthError::InvalidToken("token header without kid".into())
);
}

#[test]
fn test_decode_token_with_wrong_algorithm() {
let sut = SetupTests::new(false, true);

let token_data =
sut.manager
.decode_token(&sut.token, &sut.jwk_set, "aud".into(), "iss".into());

assert!(token_data.is_err());
assert_eq!(
token_data.unwrap_err(),
AuthError::InvalidToken("token validation error".into())
);
}
}

0 comments on commit 85d5bf7

Please sign in to comment.