oswilno/crates/actix-jwt-session/tests/ensure_redis_flow.rs

190 lines
5.1 KiB
Rust

use std::sync::Arc;
use actix_jwt_session::*;
use actix_web::http::{Method, 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 serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
struct Claims {
id: Uuid,
subject: String,
}
impl actix_jwt_session::Claims for Claims {
fn jti(&self) -> Uuid {
self.id
}
fn subject(&self) -> &str {
&self.subject
}
}
#[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(false).unwrap();
let (storage, factory) = RedisMiddlewareFactory::<Claims>::build(
Arc::new(keys.encoding_key),
Arc::new(keys.decoding_key),
Algorithm::EdDSA,
)
.with_pool(redis.clone())
.with_jwt_header(JWT_HEADER_NAME)
.with_refresh_header(REFRESH_HEADER_NAME)
.with_jwt_cookie(JWT_COOKIE_NAME)
.with_refresh_cookie(REFRESH_COOKIE_NAME)
.finish();
let app = App::new()
.app_data(Data::new(storage.clone()))
.wrap(factory.clone())
.app_data(Data::new(redis.clone()))
.app_data(Data::new(JwtTtl(Duration::days(10))))
.app_data(Data::new(RefreshTtl(Duration::days(10))))
.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(),
subject: "foo".to_string(),
};
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);
let auth_bearer = res
.headers()
.get(JWT_HEADER_NAME)
.unwrap()
.to_str()
.unwrap();
let refresh_bearer = res
.headers()
.get(REFRESH_HEADER_NAME)
.unwrap()
.to_str()
.unwrap();
let res = test::call_service(
&app,
test::TestRequest::default()
.uri("/s")
.method(Method::GET)
.insert_header((JWT_HEADER_NAME, auth_bearer))
.to_request(),
)
.await;
assert_eq!(res.status(), StatusCode::OK);
let res = test::call_service(
&app,
test::TestRequest::default()
.uri("/out")
.method(Method::POST)
.insert_header((JWT_HEADER_NAME, auth_bearer))
.to_request(),
)
.await;
assert_eq!(res.status(), StatusCode::OK);
let res = test::try_call_service(
&app,
test::TestRequest::default()
.uri("/s")
.method(Method::GET)
.insert_header((JWT_HEADER_NAME, auth_bearer))
.to_request(),
)
.await;
let err = res
.expect_err("Must be unauthorized")
.as_error::<actix_jwt_session::Error>()
.expect("Must be authorization error")
.clone();
assert_eq!(err, actix_jwt_session::Error::InvalidSession);
}
#[post("/in")]
async fn sign_in(
store: Data<SessionStorage>,
claims: Json<Claims>,
jwt_ttl: Data<JwtTtl>,
refresh_ttl: Data<RefreshTtl>,
) -> Result<HttpResponse, actix_web::Error> {
let claims = claims.into_inner();
let store = store.into_inner();
let pair = store
.clone()
.store(claims, *jwt_ttl.into_inner(), *refresh_ttl.into_inner())
.await
.unwrap();
Ok(HttpResponse::Ok()
.append_header((JWT_HEADER_NAME, pair.jwt.encode().unwrap()))
.append_header((REFRESH_HEADER_NAME, pair.refresh.encode().unwrap()))
.finish())
}
#[post("/out")]
async fn sign_out(store: Data<SessionStorage>, auth: Authenticated<Claims>) -> HttpResponse {
let store = store.into_inner();
store.erase::<Claims>(auth.id).await.unwrap();
HttpResponse::Ok().finish()
}
#[get("/s")]
async fn session(auth: Authenticated<Claims>) -> HttpResponse {
HttpResponse::Ok().json(&*auth)
}
#[get("/")]
async fn root() -> HttpResponse {
HttpResponse::Ok().finish()
}