oswilno/crates/actix-jwt-session/tests/ensure_redis_flow.rs
2023-08-14 12:30:32 +02:00

139 lines
3.6 KiB
Rust

use std::sync::Arc;
use actix_jwt_session::{Authenticated, RedisMiddlewareFactory, RedisStorage, TokenStorage};
use actix_web::http::StatusCode;
use actix_web::web::{Data, Json};
use actix_web::HttpResponse;
use actix_web::{get, post};
use actix_web::{http::header::ContentType, test, App};
use jsonwebtoken::*;
use ring::rand::SystemRandom;
use ring::signature::{Ed25519KeyPair, KeyPair};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
struct Claims {
id: Uuid,
}
impl actix_jwt_session::Claims for Claims {
fn jti(&self) -> Uuid {
self.id
}
}
#[tokio::test(flavor = "multi_thread")]
async fn not_authenticated() {
let redis = {
use redis_async_pool::{RedisConnectionManager, RedisPool};
RedisPool::new(
RedisConnectionManager::new(
redis::Client::open("redis://localhost:6379").expect("Fail to connect to redis"),
true,
None,
),
5,
)
};
let keys = JwtSigningKeys::generate().unwrap();
let factory = RedisMiddlewareFactory::<Claims>::new(
Arc::new(keys.encoding_key),
Arc::new(keys.decoding_key),
Algorithm::EdDSA,
redis.clone(),
);
let app = App::new()
.app_data(factory.storage())
.wrap(factory.clone())
.app_data(Data::new(redis.clone()))
.service(sign_in)
.service(sign_out)
.service(session)
.service(root);
let app = actix_web::test::init_service(app).await;
let res = test::call_service(
&app,
test::TestRequest::default()
.insert_header(ContentType::plaintext())
.to_request(),
)
.await;
assert!(res.status().is_success());
let res = test::call_service(
&app,
test::TestRequest::default()
.uri("/s")
.insert_header(ContentType::plaintext())
.to_request(),
)
.await;
assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
let origina_claims = Claims { id: Uuid::new_v4() };
let res = test::call_service(
&app,
test::TestRequest::default()
.uri("/in")
.method(actix_web::http::Method::POST)
.insert_header(ContentType::json())
.set_json(&origina_claims)
.to_request(),
)
.await;
assert_eq!(res.status(), StatusCode::OK);
}
#[post("/in")]
async fn sign_in(
store: Data<RedisStorage<Claims>>,
claims: Json<Claims>,
) -> Result<HttpResponse, actix_web::Error> {
let claims = claims.into_inner();
let store = store.into_inner();
store
.clone()
.set_by_jti(claims, std::time::Duration::from_secs(300))
.await
.unwrap();
Ok(HttpResponse::Ok().body(""))
}
#[post("/out")]
async fn sign_out(_store: Data<RedisStorage<Claims>>) -> HttpResponse {
HttpResponse::Ok().body("")
}
#[get("/s")]
async fn session(auth: Authenticated<Claims>) -> HttpResponse {
HttpResponse::Ok().json(&*auth)
}
#[get("/")]
async fn root() -> HttpResponse {
HttpResponse::Ok().body("")
}
pub struct JwtSigningKeys {
encoding_key: EncodingKey,
decoding_key: DecodingKey,
}
impl JwtSigningKeys {
fn generate() -> Result<Self, Box<dyn std::error::Error>> {
let doc = Ed25519KeyPair::generate_pkcs8(&SystemRandom::new())?;
let keypair = Ed25519KeyPair::from_pkcs8(doc.as_ref())?;
let encoding_key = EncodingKey::from_ed_der(doc.as_ref());
let decoding_key = DecodingKey::from_ed_der(keypair.public_key().as_ref());
Ok(JwtSigningKeys {
encoding_key,
decoding_key,
})
}
}