monorepo/orizentic/tests/integration_test.rs

430 lines
14 KiB
Rust
Raw Permalink Normal View History

2023-09-19 22:31:30 +00:00
extern crate chrono;
extern crate orizentic;
use orizentic::filedb::*;
use orizentic::*;
use std::fs;
use std::ops;
use std::thread;
use std::time;
struct FileCleanup(String);
impl FileCleanup {
fn new(path: &str) -> FileCleanup {
FileCleanup(String::from(path))
}
}
impl ops::Drop for FileCleanup {
fn drop(&mut self) {
fs::remove_file(&self.0).expect("failed to remove time series file");
}
}
#[test]
fn can_create_a_new_claimset() {
let mut ctx = OrizenticCtx::new(Secret("abcdefg".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
assert_eq!(claims.audience, Username::from("Savanni"));
match claims.expiration {
Some(ttl) => assert_eq!(ttl - claims.issued_at, chrono::Duration::seconds(3600)),
None => panic!("ttl should not be None"),
}
assert_eq!(claims.issuer, Issuer(String::from("test")));
assert_eq!(claims.resource, ResourceName(String::from("resource-1")));
assert_eq!(
claims.permissions,
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
])
);
{
let tok_list = ctx.list_claimsets();
assert_eq!(tok_list.len(), 1);
assert!(tok_list.contains(&&claims));
}
let claims2 = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-2")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims2.clone());
assert_ne!(claims2.id, claims.id);
assert_eq!(claims2.resource, ResourceName(String::from("resource-2")));
let tok_list = ctx.list_claimsets();
assert_eq!(tok_list.len(), 2);
assert!(tok_list.contains(&&claims));
assert!(tok_list.contains(&&claims2));
}
#[test]
fn can_retrieve_claim_by_id() {
let mut ctx = OrizenticCtx::new(Secret("abcdefg".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
let claims2 = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-2")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
ctx.add_claimset(claims2.clone());
assert_eq!(ctx.find_claimset(&claims.id), Some(&claims));
assert_eq!(ctx.find_claimset(&claims2.id), Some(&claims2));
ctx.revoke_claimset(&claims);
assert_eq!(ctx.find_claimset(&claims.id), None);
assert_eq!(ctx.find_claimset(&claims2.id), Some(&claims2));
}
#[test]
fn can_revoke_claim_by_id() {
let mut ctx = OrizenticCtx::new(Secret("abcdefg".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
let claims2 = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-2")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
ctx.add_claimset(claims2.clone());
assert_eq!(ctx.find_claimset(&claims.id), Some(&claims));
assert_eq!(ctx.find_claimset(&claims2.id), Some(&claims2));
ctx.revoke_by_uuid(&claims.id);
assert_eq!(ctx.find_claimset(&claims.id), None);
assert_eq!(ctx.find_claimset(&claims2.id), Some(&claims2));
}
#[test]
fn can_revoke_a_token() {
let mut ctx = OrizenticCtx::new(Secret("abcdefg".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
let claims2 = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-2")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
ctx.add_claimset(claims2.clone());
ctx.revoke_claimset(&claims);
let tok_list = ctx.list_claimsets();
assert_eq!(tok_list.len(), 1);
assert!(!tok_list.contains(&&claims));
assert!(tok_list.contains(&&claims2));
}
#[test]
fn rejects_tokens_with_an_invalid_secret() {
let mut ctx1 = OrizenticCtx::new(Secret("ctx1".to_string().into_bytes()), Vec::new());
let ctx2 = OrizenticCtx::new(Secret("ctx2".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx1.add_claimset(claims.clone());
let encoded_token = ctx1.encode_claimset(&claims).ok().unwrap();
assert!(ctx2.decode_and_validate_text(encoded_token.text).is_err());
}
#[test]
fn rejects_tokens_that_are_absent_from_the_database() {
let mut ctx = OrizenticCtx::new(Secret("ctx".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
let encoded_token = ctx.encode_claimset(&claims).ok().unwrap();
ctx.revoke_claimset(&claims);
assert!(ctx.decode_and_validate_text(encoded_token.text).is_err());
}
#[test]
fn validates_present_tokens_with_a_valid_secret() {
let mut ctx = OrizenticCtx::new(Secret("ctx".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
let encoded_token = ctx.encode_claimset(&claims).ok().unwrap();
assert!(ctx.decode_and_validate_text(encoded_token.text).is_ok());
}
#[test]
fn rejects_expired_tokens() {
let mut ctx = OrizenticCtx::new(Secret("ctx".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(1))),
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
thread::sleep(time::Duration::from_secs(2));
let encoded_token = ctx.encode_claimset(&claims).ok().unwrap();
assert!(ctx.decode_and_validate_text(encoded_token.text).is_err());
}
#[test]
fn accepts_tokens_that_have_no_expiration() {
let mut ctx = OrizenticCtx::new(Secret("ctx".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
None,
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
let encoded_token = ctx.encode_claimset(&claims).ok().unwrap();
assert!(ctx.decode_and_validate_text(encoded_token.text).is_ok());
}
#[test]
fn authorizes_a_token_with_the_correct_resource_and_permissions() {
let mut ctx = OrizenticCtx::new(Secret("ctx".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
None,
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
let encoded_token = ctx.encode_claimset(&claims).ok().unwrap();
let token = ctx
.decode_and_validate_text(encoded_token.text)
.ok()
.unwrap();
let res = token.check_authorizations(|rn: &ResourceName, perms: &Permissions| {
*rn == ResourceName(String::from("resource-1")) && perms.0.contains(&String::from("grant"))
});
assert!(res);
}
#[test]
fn rejects_a_token_with_the_incorrect_permissions() {
let mut ctx = OrizenticCtx::new(Secret("ctx".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
None,
ResourceName(String::from("resource-1")),
Username::from("Savanni"),
Permissions(vec![String::from("read"), String::from("write")]),
);
ctx.add_claimset(claims.clone());
let encoded_token = ctx.encode_claimset(&claims).ok().unwrap();
let token = ctx
.decode_and_validate_text(encoded_token.text)
.ok()
.unwrap();
let res = token.check_authorizations(|rn: &ResourceName, perms: &Permissions| {
*rn == ResourceName(String::from("resource-1")) && perms.0.contains(&String::from("grant"))
});
assert!(!res);
}
#[test]
fn rejects_a_token_with_the_incorrect_resource_name() {
let mut ctx = OrizenticCtx::new(Secret("ctx".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
None,
ResourceName(String::from("resource-2")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
let encoded_token = ctx.encode_claimset(&claims).ok().unwrap();
let token = ctx
.decode_and_validate_text(encoded_token.text)
.ok()
.unwrap();
let res = token.check_authorizations(|rn: &ResourceName, perms: &Permissions| {
*rn == ResourceName(String::from("resource-1")) && perms.0.contains(&String::from("grant"))
});
assert!(!res);
}
#[test]
fn claims_serialize_to_json() {
let claims = ClaimSet::new(
Issuer(String::from("test")),
None,
ResourceName(String::from("resource-2")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
let expected_jti = format!("\"jti\":\"{}\"", claims.id);
let claim_str = claims.to_json().expect("to_json threw an error");
//.expect(assert!(false, format!("[claims_serilazie_to_json] {}", err)));
assert!(claim_str.contains(&expected_jti));
let claims_ = ClaimSet::from_json(&claim_str).expect("from_json threw an error");
assert_eq!(claims, claims_);
}
#[test]
fn save_and_load() {
let _file_cleanup = FileCleanup::new("var/claims.db");
let mut ctx = OrizenticCtx::new(Secret("ctx".to_string().into_bytes()), Vec::new());
let claims = ClaimSet::new(
Issuer(String::from("test")),
None,
ResourceName(String::from("resource-2")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims.clone());
let claims2 = ClaimSet::new(
Issuer(String::from("test")),
Some(TTL(chrono::Duration::seconds(3600))),
ResourceName(String::from("resource-2")),
Username::from("Savanni"),
Permissions(vec![
String::from("read"),
String::from("write"),
String::from("grant"),
]),
);
ctx.add_claimset(claims2.clone());
let res = save_claims_to_file(&ctx.list_claimsets(), &String::from("var/claims.db"));
assert!(res.is_ok());
let claimset = load_claims_from_file(&String::from("var/claims.db"));
match claimset {
Ok(claimset_) => {
assert!(claimset_.contains(&claims));
assert!(claimset_.contains(&claims2));
}
Err(err) => assert!(false, "{}", err),
}
}