Add session system

This commit is contained in:
Pierre HUBERT 2023-09-02 09:12:36 +02:00
parent 0ac1480572
commit 129d23f671
7 changed files with 260 additions and 17 deletions

View File

@ -30,7 +30,7 @@ dependencies = [
"actix-service", "actix-service",
"actix-utils", "actix-utils",
"ahash", "ahash",
"base64", "base64 0.21.3",
"bitflags 2.4.0", "bitflags 2.4.0",
"brotli", "brotli",
"bytes", "bytes",
@ -58,6 +58,22 @@ dependencies = [
"zstd", "zstd",
] ]
[[package]]
name = "actix-identity"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1224c9f9593dc27c9077b233ce04adedc1d7febcfc35ee9f53ea3c24df180bec"
dependencies = [
"actix-service",
"actix-session",
"actix-utils",
"actix-web",
"anyhow",
"futures-core",
"serde",
"tracing",
]
[[package]] [[package]]
name = "actix-macros" name = "actix-macros"
version = "0.2.4" version = "0.2.4"
@ -130,6 +146,23 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
[[package]]
name = "actix-session"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43da8b818ae1f11049a4d218975345fe8e56ce5a5f92c11f972abcff5ff80e87"
dependencies = [
"actix-service",
"actix-utils",
"actix-web",
"anyhow",
"async-trait",
"derive_more",
"serde",
"serde_json",
"tracing",
]
[[package]] [[package]]
name = "actix-utils" name = "actix-utils"
version = "3.0.1" version = "3.0.1"
@ -207,6 +240,41 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aead"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
"crypto-common",
"generic-array",
]
[[package]]
name = "aes"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "aes-gcm"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237"
dependencies = [
"aead",
"aes",
"cipher",
"ctr",
"ghash",
"subtle",
]
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.8.3" version = "0.8.3"
@ -291,6 +359,23 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "anyhow"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "async-trait"
version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.29",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -312,6 +397,12 @@ dependencies = [
"rustc-demangle", "rustc-demangle",
] ]
[[package]]
name = "base64"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.21.3" version = "0.21.3"
@ -397,6 +488,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.4.2" version = "4.4.2"
@ -455,7 +556,14 @@ version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
dependencies = [ dependencies = [
"aes-gcm",
"base64 0.20.0",
"hkdf",
"hmac",
"percent-encoding", "percent-encoding",
"rand",
"sha2",
"subtle",
"time", "time",
"version_check", "version_check",
] ]
@ -501,9 +609,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [ dependencies = [
"generic-array", "generic-array",
"rand_core",
"typenum", "typenum",
] ]
[[package]]
name = "ctr"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
dependencies = [
"cipher",
]
[[package]] [[package]]
name = "deranged" name = "deranged"
version = "0.3.8" version = "0.3.8"
@ -531,6 +649,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"block-buffer", "block-buffer",
"crypto-common", "crypto-common",
"subtle",
] ]
[[package]] [[package]]
@ -695,6 +814,16 @@ dependencies = [
"wasi", "wasi",
] ]
[[package]]
name = "ghash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40"
dependencies = [
"opaque-debug",
"polyval",
]
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.28.0" version = "0.28.0"
@ -738,6 +867,24 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "hkdf"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
dependencies = [
"hmac",
]
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
]
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.9" version = "0.2.9"
@ -835,6 +982,15 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "ipnet" name = "ipnet"
version = "2.8.0" version = "2.8.0"
@ -900,7 +1056,7 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608aa1b7148a6eeab631c6267deca33407ff851ab50eea115e52c13a9bb184ee" checksum = "608aa1b7148a6eeab631c6267deca33407ff851ab50eea115e52c13a9bb184ee"
dependencies = [ dependencies = [
"base64", "base64 0.21.3",
"log", "log",
"reqwest", "reqwest",
"serde", "serde",
@ -1014,6 +1170,12 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.57" version = "0.10.57"
@ -1111,6 +1273,18 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "polyval"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb"
dependencies = [
"cfg-if",
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.17"
@ -1209,7 +1383,7 @@ version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
dependencies = [ dependencies = [
"base64", "base64 0.21.3",
"bytes", "bytes",
"encoding_rs", "encoding_rs",
"futures-core", "futures-core",
@ -1372,6 +1546,17 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "sha2"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.1" version = "1.4.1"
@ -1422,6 +1607,12 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.109"
@ -1610,6 +1801,16 @@ dependencies = [
"tinyvec", "tinyvec",
] ]
[[package]]
name = "universal-hash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
"crypto-common",
"subtle",
]
[[package]] [[package]]
name = "url" name = "url"
version = "2.4.1" version = "2.4.1"
@ -1649,7 +1850,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
name = "virtweb_backend" name = "virtweb_backend"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"actix-identity",
"actix-remote-ip", "actix-remote-ip",
"actix-session",
"actix-web", "actix-web",
"clap", "clap",
"env_logger", "env_logger",

View File

@ -13,4 +13,6 @@ light-openid = "1.0.1"
lazy_static = "1.4.0" lazy_static = "1.4.0"
actix-web = "4" actix-web = "4"
actix-remote-ip = "0.1.0" actix-remote-ip = "0.1.0"
actix-session = { version = "0.7.2", features = ["cookie-session"] }
actix-identity = "0.5.2"
serde = { version = "1.0.175", features = ["derive"] } serde = { version = "1.0.175", features = ["derive"] }

View File

@ -20,6 +20,10 @@ pub struct AppConfig {
#[clap(long, env, default_value = "")] #[clap(long, env, default_value = "")]
secret: String, secret: String,
/// Specify whether the cookie should be transmitted only over secure connections
#[clap(long, env)]
pub cookie_secure: bool,
/// Auth username /// Auth username
#[arg(long, env, default_value = "admin")] #[arg(long, env, default_value = "admin")]
pub auth_username: String, pub auth_username: String,
@ -38,13 +42,12 @@ pub struct AppConfig {
/// URL where the OpenID configuration can be found /// URL where the OpenID configuration can be found
#[arg( #[arg(
long, long,
env, env,
default_value = "http://localhost:9001/.well-known/openid-configuration" default_value = "http://localhost:9001/.well-known/openid-configuration"
)] )]
pub oidc_configuration_url: String, pub oidc_configuration_url: String,
/// Disable OpenID authentication /// Disable OpenID authentication
#[arg(long, env)] #[arg(long, env)]
pub disable_oidc: bool, pub disable_oidc: bool,
@ -83,11 +86,11 @@ impl AppConfig {
let mut secret = self.secret.as_str(); let mut secret = self.secret.as_str();
if cfg!(debug_assertions) && secret.is_empty() { if cfg!(debug_assertions) && secret.is_empty() {
secret = "DEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEY"; secret = "DEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEY";
} }
if secret.is_empty() { if secret.is_empty() {
panic!("SECRET is undefined or too short (min 30 chars)!") panic!("SECRET is undefined or too short (min 64 chars)!")
} }
secret secret

View File

@ -0,0 +1,8 @@
/// Name of the cookie that contains session information
pub const SESSION_COOKIE_NAME: &str = "X-auth-token";
/// Maximum session duration after inactivity, in seconds
pub const MAX_INACTIVITY_DURATION: u64 = 60 * 30;
/// Maximum session duration (6 hours)
pub const MAX_SESSION_DURATION: u64 = 3600 * 6;

View File

@ -1 +1 @@
pub mod server_controller; pub mod server_controller;

View File

@ -1,2 +1,3 @@
pub mod app_config; pub mod app_config;
pub mod controllers; pub mod constants;
pub mod controllers;

View File

@ -1,7 +1,16 @@
use actix_identity::config::LogoutBehaviour;
use actix_identity::IdentityMiddleware;
use actix_remote_ip::RemoteIPConfig; use actix_remote_ip::RemoteIPConfig;
use actix_web::{App, HttpServer, web}; use actix_session::storage::CookieSessionStore;
use virtweb_backend::app_config::AppConfig; use actix_session::SessionMiddleware;
use actix_web::cookie::{Key, SameSite};
use actix_web::middleware::Logger; use actix_web::middleware::Logger;
use actix_web::{web, App, HttpServer};
use std::time::Duration;
use virtweb_backend::app_config::AppConfig;
use virtweb_backend::constants::{
MAX_INACTIVITY_DURATION, MAX_SESSION_DURATION, SESSION_COOKIE_NAME,
};
use virtweb_backend::controllers::server_controller; use virtweb_backend::controllers::server_controller;
#[actix_web::main] #[actix_web::main]
@ -11,14 +20,31 @@ async fn main() -> std::io::Result<()> {
log::info!("Start to listen on {}", AppConfig::get().listen_address); log::info!("Start to listen on {}", AppConfig::get().listen_address);
HttpServer::new(|| { HttpServer::new(|| {
let session_mw = SessionMiddleware::builder(
CookieSessionStore::default(),
Key::from(AppConfig::get().secret().as_bytes()),
)
.cookie_name(SESSION_COOKIE_NAME.to_string())
.cookie_secure(AppConfig::get().cookie_secure)
.cookie_same_site(SameSite::Strict)
.build();
let identity_middleware = IdentityMiddleware::builder()
.logout_behaviour(LogoutBehaviour::PurgeSession)
.visit_deadline(Some(Duration::from_secs(MAX_INACTIVITY_DURATION)))
.login_deadline(Some(Duration::from_secs(MAX_SESSION_DURATION)))
.build();
App::new() App::new()
.wrap(Logger::default()) .wrap(Logger::default())
.wrap(identity_middleware)
.wrap(session_mw)
.app_data(web::Data::new(RemoteIPConfig { .app_data(web::Data::new(RemoteIPConfig {
proxy: AppConfig::get().proxy_ip.clone() proxy: AppConfig::get().proxy_ip.clone(),
})) }))
.route("/", web::get().to(server_controller::root_index)) .route("/", web::get().to(server_controller::root_index))
}) })
.bind(&AppConfig::get().listen_address)? .bind(&AppConfig::get().listen_address)?
.run() .run()
.await .await
} }