From 3498e57e043e968426fe0c1b5c28903e487d084c Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Tue, 10 May 2022 08:29:25 +0100 Subject: [PATCH] Implement web authentication session validation --- Cargo.lock | 77 ++++++++- Cargo.toml | 3 + lib/src/sql/algorithm.rs | 3 + src/err/mod.rs | 46 ++++-- src/net/conf.rs | 59 ------- src/net/export.rs | 2 +- src/net/fail.rs | 53 ++++--- src/net/key.rs | 18 +-- src/net/mod.rs | 2 +- src/net/session.rs | 333 +++++++++++++++++++++++++++++++++++++++ src/net/sql.rs | 4 +- 11 files changed, 491 insertions(+), 109 deletions(-) delete mode 100644 src/net/conf.rs create mode 100644 src/net/session.rs diff --git a/Cargo.lock b/Cargo.lock index ee060007..f0586d78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,7 +309,7 @@ dependencies = [ "num-integer", "num-traits", "serde", - "time", + "time 0.1.44", "winapi", ] @@ -1126,6 +1126,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9051c17f81bae79440afa041b3a278e1de71bfb96d32454b477fd4703ccb6f" +dependencies = [ + "base64", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1389,6 +1403,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.10.0" @@ -1528,6 +1551,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pem" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947" +dependencies = [ + "base64", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1769,6 +1801,15 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "quote" version = "1.0.18" @@ -2210,6 +2251,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +[[package]] +name = "simple_asn1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a762b1c38b9b990c694b9c2f8abe3372ce6a9ceaae6bca39cfc46e054f45745" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time 0.3.9", +] + [[package]] name = "sized-chunks" version = "0.6.5" @@ -2290,6 +2343,8 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" name = "surreal" version = "0.0.0" dependencies = [ + "argon2", + "base64", "bytes", "chrono", "clap", @@ -2297,6 +2352,7 @@ dependencies = [ "futures 0.3.21", "http", "hyper", + "jsonwebtoken", "log", "once_cell", "rand 0.8.5", @@ -2527,6 +2583,25 @@ dependencies = [ "winapi", ] +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "quickcheck", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index d05fd416..1acba1bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,8 @@ panic = 'abort' codegen-units = 1 [dependencies] +argon2 = "0.4.0" +base64 = "0.13.0" bytes = "1.1.0" chrono = { version = "0.4.19", features = ["serde"] } clap = "3.1.17" @@ -23,6 +25,7 @@ fern = { version = "0.6.1", features = ["colored"] } futures = "0.3.21" http = "0.2.7" hyper = "0.14.18" +jsonwebtoken = "8.1.0" log = "0.4.17" once_cell = "1.10.0" rand = "0.8.5" diff --git a/lib/src/sql/algorithm.rs b/lib/src/sql/algorithm.rs index 1cd08296..39f41f31 100644 --- a/lib/src/sql/algorithm.rs +++ b/lib/src/sql/algorithm.rs @@ -7,6 +7,7 @@ use std::fmt; #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum Algorithm { + EdDSA, Es256, Es384, Es512, @@ -30,6 +31,7 @@ impl Default for Algorithm { impl fmt::Display for Algorithm { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + Algorithm::EdDSA => write!(f, "EDDSA"), Algorithm::Es256 => write!(f, "ES256"), Algorithm::Es384 => write!(f, "ES384"), Algorithm::Es512 => write!(f, "ES512"), @@ -48,6 +50,7 @@ impl fmt::Display for Algorithm { pub fn algorithm(i: &str) -> IResult<&str, Algorithm> { alt(( + map(tag("EDDSA"), |_| Algorithm::EdDSA), map(tag("ES256"), |_| Algorithm::Es256), map(tag("ES384"), |_| Algorithm::Es384), map(tag("ES512"), |_| Algorithm::Es512), diff --git a/src/err/mod.rs b/src/err/mod.rs index 338dc367..342f5f60 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -1,10 +1,11 @@ -use http::Error as HttpError; -use hyper::Error as HyperError; +use base64::DecodeError as Base64Error; +use jsonwebtoken::errors::Error as JWTError; use reqwest::Error as ReqwestError; use serde_cbor::error::Error as CborError; use serde_json::error::Error as JsonError; use serde_pack::encode::Error as PackError; use std::io::Error as IoError; +use std::string::FromUtf8Error as Utf8Error; use surrealdb::Error as DbError; use thiserror::Error; @@ -13,29 +14,44 @@ pub enum Error { #[error("The request body contains invalid data")] Request, - #[error("{0}")] + #[error("There was a problem with authentication")] + InvalidAuth, + + #[error("There was a problem with the database: {0}")] Db(#[from] DbError), - #[error("IO error: {0}")] + #[error("Couldn't open the specified file: {0}")] Io(#[from] IoError), - #[error("HTTP Error: {0}")] - Hyper(#[from] HyperError), - - #[error("HTTP Error: {0}")] - Http(#[from] HttpError), - - #[error("JSON Error: {0}")] + #[error("There was an error serializing to JSON: {0}")] Json(#[from] JsonError), - #[error("CBOR Error: {0}")] + #[error("There was an error serializing to CBOR: {0}")] Cbor(#[from] CborError), - #[error("PACK Error: {0}")] + #[error("There was an error serializing to MessagePack: {0}")] Pack(#[from] PackError), - #[error("Reqwest Error: {0}")] - Reqwest(#[from] ReqwestError), + #[error("There was an error with the remote request: {0}")] + Remote(#[from] ReqwestError), } impl warp::reject::Reject for Error {} + +impl From for Error { + fn from(_: Base64Error) -> Error { + Error::InvalidAuth + } +} + +impl From for Error { + fn from(_: Utf8Error) -> Error { + Error::InvalidAuth + } +} + +impl From for Error { + fn from(_: JWTError) -> Error { + Error::InvalidAuth + } +} diff --git a/src/net/conf.rs b/src/net/conf.rs deleted file mode 100644 index 488170d5..00000000 --- a/src/net/conf.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::net::SocketAddr; -use std::sync::Arc; -use surrealdb::Auth; -use surrealdb::Session; -use warp::Filter; - -pub fn build() -> impl Filter + Copy { - // Enable on any path - let conf = warp::any(); - // Add remote ip address - let conf = conf.and(warp::filters::addr::remote()); - // Add authorization header - let conf = conf.and(warp::header::optional::("authorization")); - // Add http origin header - let conf = conf.and(warp::header::optional::("origin")); - // Add session id header - let conf = conf.and(warp::header::optional::("id")); - // Add namespace header - let conf = conf.and(warp::header::optional::("ns")); - // Add database header - let conf = conf.and(warp::header::optional::("db")); - // Process all headers - conf.map(process) -} - -fn process( - ip: Option, - au: Option, - or: Option, - id: Option, - ns: Option, - db: Option, -) -> Session { - // Create session - let conf = Session { - au: Arc::new(Auth::default()), - ip: ip.map(|v| v.to_string()), - or, - id, - ns, - db, - sc: None, - sd: None, - }; - // Parse authentication - match au { - Some(auth) if auth.starts_with("Basic") => basic(auth, conf), - Some(auth) if auth.starts_with("Bearer") => token(auth, conf), - _ => conf, - } -} - -fn basic(_auth: String, conf: Session) -> Session { - conf -} - -fn token(_auth: String, conf: Session) -> Session { - conf -} diff --git a/src/net/export.rs b/src/net/export.rs index 7b0c165f..22ca7704 100644 --- a/src/net/export.rs +++ b/src/net/export.rs @@ -1,7 +1,7 @@ -use crate::net::conf; // use crate::net::DB; // use hyper::body::Body; // use surrealdb::dbs::export; +use crate::net::session; use surrealdb::Session; use warp::Filter; diff --git a/src/net/fail.rs b/src/net/fail.rs index eec9b2d8..eb3f8676 100644 --- a/src/net/fail.rs +++ b/src/net/fail.rs @@ -14,7 +14,28 @@ struct Message { } pub async fn recover(err: warp::Rejection) -> Result { - if err.is_not_found() { + if let Some(err) = err.find::() { + match err { + Error::InvalidAuth => Ok(warp::reply::with_status( + warp::reply::json(&Message { + code: 403, + details: Some("Authentication failed".to_string()), + description: Some("Your authentication details are invalid. Reauthenticate using valid authentication parameters.".to_string()), + information: Some(err.to_string()), + }), + StatusCode::FORBIDDEN, + )), + _ => Ok(warp::reply::with_status( + warp::reply::json(&Message { + code: 400, + details: Some("Request problems detected".to_string()), + description: Some("There is a problem with your request. Refer to the documentation for further information.".to_string()), + information: Some(err.to_string()), + }), + StatusCode::BAD_REQUEST, + )) + } + } else if err.is_not_found() { Ok(warp::reply::with_status( warp::reply::json(&Message { code: 404, @@ -24,16 +45,6 @@ pub async fn recover(err: warp::Rejection) -> Result() { - Ok(warp::reply::with_status( - warp::reply::json(&Message { - code: 400, - details: Some("Request problems detected".to_string()), - description: Some("There is a problem with your request. Refer to the documentation for further information.".to_string()), - information: Some(err.to_string()), - }), - StatusCode::BAD_REQUEST, - )) } else if err.find::().is_some() { Ok(warp::reply::with_status( warp::reply::json(&Message { @@ -44,6 +55,16 @@ pub async fn recover(err: warp::Rejection) -> Result().is_some() { + Ok(warp::reply::with_status( + warp::reply::json(&Message { + code: 412, + details: Some("Request problems detected".to_string()), + description: Some("The request appears to be missing a required header. Refer to the documentation for request requirements.".to_string()), + information: None, + }), + StatusCode::PRECONDITION_FAILED, + )) } else if err.find::().is_some() { Ok(warp::reply::with_status( warp::reply::json(&Message { @@ -64,16 +85,6 @@ pub async fn recover(err: warp::Rejection) -> Result().is_some() { - Ok(warp::reply::with_status( - warp::reply::json(&Message { - code: 412, - details: Some("Request problems detected".to_string()), - description: Some("The request appears to be missing a required header. Refer to the documentation for request requirements.".to_string()), - information: None, - }), - StatusCode::PRECONDITION_FAILED, - )) } else if err.find::().is_some() { Ok(warp::reply::with_status( warp::reply::json(&Message { diff --git a/src/net/key.rs b/src/net/key.rs index 26636896..6a3e6bc9 100644 --- a/src/net/key.rs +++ b/src/net/key.rs @@ -1,7 +1,7 @@ use crate::err::Error; -use crate::net::conf; use crate::net::head; use crate::net::output; +use crate::net::session; use crate::net::DB; use bytes::Bytes; use serde::Deserialize; @@ -35,7 +35,7 @@ pub fn config() -> impl Filter(http::header::CONTENT_TYPE.as_str())) .and(path!("key" / String).and(warp::path::end())) .and(warp::query()) @@ -43,7 +43,7 @@ pub fn config() -> impl Filter(http::header::CONTENT_TYPE.as_str())) .and(path!("key" / String).and(warp::path::end())) .and(warp::body::content_length_limit(MAX)) @@ -52,7 +52,7 @@ pub fn config() -> impl Filter(http::header::CONTENT_TYPE.as_str())) .and(path!("key" / String).and(warp::path::end())) .and_then(delete_all); @@ -66,14 +66,14 @@ pub fn config() -> impl Filter(http::header::CONTENT_TYPE.as_str())) .and(path!("key" / String / String).and(warp::path::end())) .and_then(select_one); // Set create method let create = warp::any() .and(warp::post()) - .and(conf::build()) + .and(session::build()) .and(warp::header::(http::header::CONTENT_TYPE.as_str())) .and(path!("key" / String / String).and(warp::path::end())) .and(warp::body::content_length_limit(MAX)) @@ -82,7 +82,7 @@ pub fn config() -> impl Filter(http::header::CONTENT_TYPE.as_str())) .and(path!("key" / String / String).and(warp::path::end())) .and(warp::body::content_length_limit(MAX)) @@ -91,7 +91,7 @@ pub fn config() -> impl Filter(http::header::CONTENT_TYPE.as_str())) .and(path!("key" / String / String).and(warp::path::end())) .and(warp::body::content_length_limit(MAX)) @@ -100,7 +100,7 @@ pub fn config() -> impl Filter(http::header::CONTENT_TYPE.as_str())) .and(path!("key" / String / String).and(warp::path::end())) .and_then(delete_one); diff --git a/src/net/mod.rs b/src/net/mod.rs index 4b016f29..2d03df7b 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -1,4 +1,3 @@ -mod conf; mod config; mod export; mod fail; @@ -8,6 +7,7 @@ mod index; mod key; mod log; mod output; +mod session; mod signin; mod signup; mod sql; diff --git a/src/net/session.rs b/src/net/session.rs new file mode 100644 index 00000000..cb032ac7 --- /dev/null +++ b/src/net/session.rs @@ -0,0 +1,333 @@ +use crate::err::Error; +use crate::net::CF; +use crate::net::DB; +use argon2::password_hash::{PasswordHash, PasswordVerifier}; +use argon2::Argon2; +use jsonwebtoken::{decode, DecodingKey, Validation}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; +use std::net::SocketAddr; +use std::sync::Arc; +use surrealdb::sql::Algorithm; +use surrealdb::sql::Thing; +use surrealdb::sql::Value; +use surrealdb::Auth; +use surrealdb::Session; +use warp::Filter; + +const BASIC: &str = "Basic "; +const TOKEN: &str = "Bearer "; + +fn config(algo: Algorithm, code: String) -> Result<(DecodingKey, Validation), Error> { + match algo { + Algorithm::Hs256 => Ok(( + DecodingKey::from_secret(code.as_ref()), + Validation::new(jsonwebtoken::Algorithm::HS256), + )), + Algorithm::Hs384 => Ok(( + DecodingKey::from_secret(code.as_ref()), + Validation::new(jsonwebtoken::Algorithm::HS384), + )), + Algorithm::Hs512 => Ok(( + DecodingKey::from_secret(code.as_ref()), + Validation::new(jsonwebtoken::Algorithm::HS512), + )), + Algorithm::EdDSA => Ok(( + DecodingKey::from_ed_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::EdDSA), + )), + Algorithm::Es256 => Ok(( + DecodingKey::from_ec_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::ES256), + )), + Algorithm::Es384 => Ok(( + DecodingKey::from_ec_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::ES384), + )), + Algorithm::Es512 => Ok(( + DecodingKey::from_ec_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::ES384), + )), + Algorithm::Ps256 => Ok(( + DecodingKey::from_rsa_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::PS256), + )), + Algorithm::Ps384 => Ok(( + DecodingKey::from_rsa_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::PS384), + )), + Algorithm::Ps512 => Ok(( + DecodingKey::from_rsa_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::PS512), + )), + Algorithm::Rs256 => Ok(( + DecodingKey::from_rsa_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::RS256), + )), + Algorithm::Rs384 => Ok(( + DecodingKey::from_rsa_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::RS384), + )), + Algorithm::Rs512 => Ok(( + DecodingKey::from_rsa_pem(code.as_ref())?, + Validation::new(jsonwebtoken::Algorithm::RS512), + )), + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Claims { + iss: String, + iat: usize, + nbf: usize, + exp: usize, + ns: Option, + db: Option, + sc: Option, + tk: Option, + tb: Option, + id: Option, +} + +static KEY: Lazy = Lazy::new(|| DecodingKey::from_secret(&[])); + +static DUD: Lazy = Lazy::new(|| { + let mut validation = Validation::new(jsonwebtoken::Algorithm::HS256); + validation.insecure_disable_signature_validation(); + validation.validate_nbf = true; + validation.validate_exp = true; + validation +}); + +pub fn build() -> impl Filter + Clone { + // Enable on any path + let conf = warp::any(); + // Add remote ip address + let conf = conf.and(warp::filters::addr::remote()); + // Add remote ip address + let conf = conf.map(|addr: Option| addr.map(|v| v.to_string())); + // Add authorization header + let conf = conf.and(warp::header::optional::("authorization")); + // Add http origin header + let conf = conf.and(warp::header::optional::("origin")); + // Add session id header + let conf = conf.and(warp::header::optional::("id")); + // Add namespace header + let conf = conf.and(warp::header::optional::("ns")); + // Add database header + let conf = conf.and(warp::header::optional::("db")); + // Process all headers + conf.and_then(process) +} + +async fn process( + ip: Option, + au: Option, + or: Option, + id: Option, + ns: Option, + db: Option, +) -> Result { + // Create session + #[rustfmt::skip] + let session = Session { ip, or, id, ns, db, ..Default::default() }; + // Parse the authentication header + let session = match au { + // Basic authentication data was supplied + Some(auth) if auth.starts_with(BASIC) => basic(auth, session).await, + // Token authentication data was supplied + Some(auth) if auth.starts_with(TOKEN) => token(auth, session).await, + // Wrong authentication data was supplied + Some(_) => Err(Error::InvalidAuth), + // No authentication data was supplied + None => Ok(session), + }?; + // Pass the authenticated session through + Ok(session) +} + +async fn basic(auth: String, mut session: Session) -> Result { + // Get the config options + let opts = CF.get().unwrap(); + // Retrieve just the auth data + if let Some((_, auth)) = auth.split_once(' ') { + // Get a database reference + let db = DB.get().unwrap(); + // Decode the encoded auth data + let auth = base64::decode(auth)?; + // Convert the auth data to String + let auth = String::from_utf8(auth)?; + // Create a new readonly transaction + let mut tx = db.transaction(false, false).await?; + // Split the auth data into user and pass + if let Some((user, pass)) = auth.split_once(':') { + // Check that the details are not empty + if user.is_empty() || pass.is_empty() { + return Err(Error::InvalidAuth); + } + // Check if this is root authentication + if user == opts.user && pass == opts.pass { + session.au = Arc::new(Auth::Kv); + return Ok(session); + } + // Check if this is NS authentication + if let Some(ns) = &session.ns { + // Check if the supplied NS Login exists + if let Ok(nl) = tx.get_nl(ns, user).await { + // Compute the hash and verify the password + let hash = PasswordHash::new(&nl.hash).unwrap(); + if Argon2::default().verify_password(pass.as_ref(), &hash).is_ok() { + session.au = Arc::new(Auth::Ns(ns.to_owned())); + return Ok(session); + } + }; + // Check if this is DB authentication + if let Some(db) = &session.db { + // Check if the supplied DB Login exists + if let Ok(dl) = tx.get_dl(ns, db, user).await { + // Compute the hash and verify the password + let hash = PasswordHash::new(&dl.hash).unwrap(); + if Argon2::default().verify_password(pass.as_ref(), &hash).is_ok() { + session.au = Arc::new(Auth::Db(ns.to_owned(), db.to_owned())); + return Ok(session); + } + }; + } + } + } + } + // There was an auth error + Err(Error::InvalidAuth) +} + +async fn token(auth: String, mut session: Session) -> Result { + // Retrieve just the auth data + if let Some((_, auth)) = auth.split_once(' ') { + // Get a database reference + let db = DB.get().unwrap(); + // Create a new readonly transaction + let mut tx = db.transaction(false, false).await?; + // Decode the token without verifying + let token = decode::(auth, &KEY, &DUD)?; + // Check the token authentication claims + match token.claims { + // Check if this is scope token authentication + Claims { + ns: Some(ns), + db: Some(db), + sc: Some(sc), + tk: Some(tk), + tb: Some(tb), + id: Some(id), + .. + } => { + // Get the scope token + let de = tx.get_st(&ns, &db, &sc, &tk).await?; + let cf = config(de.kind, de.code)?; + // Verify the token + decode::(auth, &cf.0, &cf.1)?; + // Set the session + session.ns = Some(ns.to_owned()); + session.db = Some(db.to_owned()); + session.sc = Some(sc.to_owned()); + session.sd = Some(Value::from(Thing::from((tb, id)))); + session.au = Arc::new(Auth::Sc(ns, db, sc)); + return Ok(session); + } + // Check if this is scope authentication + Claims { + ns: Some(ns), + db: Some(db), + sc: Some(sc), + tb: Some(tb), + id: Some(id), + .. + } => { + // Get the scope + let de = tx.get_sc(&ns, &db, &sc).await?; + let cf = config(Algorithm::Hs512, de.code)?; + // Verify the token + decode::(auth, &cf.0, &cf.1)?; + // Set the session + session.ns = Some(ns.to_owned()); + session.db = Some(db.to_owned()); + session.sc = Some(sc.to_owned()); + session.sd = Some(Value::from(Thing::from((tb, id)))); + session.au = Arc::new(Auth::Sc(ns, db, sc)); + return Ok(session); + } + // Check if this is database token authentication + Claims { + ns: Some(ns), + db: Some(db), + tk: Some(tk), + .. + } => { + // Get the database token + let de = tx.get_dt(&ns, &db, &tk).await?; + let cf = config(de.kind, de.code)?; + // Verify the token + decode::(auth, &cf.0, &cf.1)?; + // Set the session + session.ns = Some(ns.to_owned()); + session.db = Some(db.to_owned()); + session.au = Arc::new(Auth::Db(ns, db)); + return Ok(session); + } + // Check if this is database authentication + Claims { + ns: Some(ns), + db: Some(db), + id: Some(id), + .. + } => { + // Get the database login + let de = tx.get_dl(&ns, &db, &id).await?; + let cf = config(Algorithm::Hs512, de.code)?; + // Verify the token + decode::(auth, &cf.0, &cf.1)?; + // Set the session + session.ns = Some(ns.to_owned()); + session.db = Some(db.to_owned()); + session.au = Arc::new(Auth::Db(ns, db)); + return Ok(session); + } + // Check if this is namespace token authentication + Claims { + ns: Some(ns), + tk: Some(tk), + .. + } => { + // Get the namespace token + let de = tx.get_nt(&ns, &tk).await?; + let cf = config(de.kind, de.code)?; + // Verify the token + decode::(auth, &cf.0, &cf.1)?; + // Set the session + session.ns = Some(ns.to_owned()); + session.au = Arc::new(Auth::Ns(ns)); + return Ok(session); + } + // Check if this is namespace authentication + Claims { + ns: Some(ns), + id: Some(id), + .. + } => { + // Get the namespace login + let de = tx.get_nl(&ns, &id).await?; + let cf = config(Algorithm::Hs512, de.code)?; + // Verify the token + decode::(auth, &cf.0, &cf.1)?; + // Set the session + session.ns = Some(ns.to_owned()); + session.au = Arc::new(Auth::Ns(ns)); + return Ok(session); + } + // There was an auth error + _ => return Err(Error::InvalidAuth), + }; + } + // There was an auth error + Err(Error::InvalidAuth) +} diff --git a/src/net/sql.rs b/src/net/sql.rs index b224d38c..31483ed9 100644 --- a/src/net/sql.rs +++ b/src/net/sql.rs @@ -1,7 +1,7 @@ use crate::err::Error; -use crate::net::conf; use crate::net::head; use crate::net::output; +use crate::net::session; use crate::net::DB; use bytes::Bytes; use futures::{FutureExt, StreamExt}; @@ -18,7 +18,7 @@ pub fn config() -> impl Filter(http::header::CONTENT_TYPE.as_str())) .and(warp::body::content_length_limit(MAX)) .and(warp::body::bytes())