Add authentication token claims data to session object

Closes #135
This commit is contained in:
Tobie Morgan Hitchcock 2022-09-17 02:52:07 +01:00
parent 4c98717f1d
commit a7444a7c8e
7 changed files with 91 additions and 13 deletions

View file

@ -22,6 +22,8 @@ pub struct Session {
pub db: Option<String>, pub db: Option<String>,
/// The currently selected authentication scope /// The currently selected authentication scope
pub sc: Option<String>, pub sc: Option<String>,
/// The current scope authentication token
pub tk: Option<Value>,
/// The current scope authentication data /// The current scope authentication data
pub sd: Option<Value>, pub sd: Option<Value>,
} }
@ -101,13 +103,14 @@ impl Session {
// Add session value // Add session value
let key = String::from("session"); let key = String::from("session");
let val: Value = Value::from(map! { let val: Value = Value::from(map! {
"ip".to_string() => self.ip.to_owned().into(),
"or".to_string() => self.or.to_owned().into(),
"id".to_string() => self.id.to_owned().into(),
"ns".to_string() => self.ns.to_owned().into(),
"db".to_string() => self.db.to_owned().into(), "db".to_string() => self.db.to_owned().into(),
"id".to_string() => self.id.to_owned().into(),
"ip".to_string() => self.ip.to_owned().into(),
"ns".to_string() => self.ns.to_owned().into(),
"or".to_string() => self.or.to_owned().into(),
"sc".to_string() => self.sc.to_owned().into(), "sc".to_string() => self.sc.to_owned().into(),
"sd".to_string() => self.sd.to_owned().into(), "sd".to_string() => self.sd.to_owned().into(),
"tk".to_string() => self.tk.to_owned().into(),
}); });
ctx.add_value(key, val); ctx.add_value(key, val);
// Output context // Output context

View file

@ -1,4 +1,5 @@
pub mod clear; pub mod clear;
pub mod parse;
pub mod signin; pub mod signin;
pub mod signup; pub mod signup;
pub mod token; pub mod token;

15
src/iam/parse.rs Normal file
View file

@ -0,0 +1,15 @@
use crate::err::Error;
use std::str;
use surrealdb::sql::json;
use surrealdb::sql::Value;
pub fn parse(value: &str) -> Result<Value, Error> {
// Extract the middle part of the token
let value = value.splitn(3, '.').skip(1).take(1).next().ok_or(Error::InvalidAuth)?;
// Decode the base64 token data content
let value = base64::decode(value).map_err(|_| Error::InvalidAuth)?;
// Convert the decoded data to a string
let value = str::from_utf8(&value).map_err(|_| Error::InvalidAuth)?;
// Parse the token data into SurrealQL
json(value).map_err(|_| Error::InvalidAuth)
}

View file

@ -144,14 +144,17 @@ pub async fn sc(
id: Some(rid.to_raw()), id: Some(rid.to_raw()),
..Claims::default() ..Claims::default()
}; };
// Create the authentication token
let enc = encode(&*HEADER, &val, &key);
// Set the authentication on the session // Set the authentication on the session
session.tk = Some(val.into());
session.ns = Some(ns.to_owned()); session.ns = Some(ns.to_owned());
session.db = Some(db.to_owned()); session.db = Some(db.to_owned());
session.sc = Some(sc.to_owned()); session.sc = Some(sc.to_owned());
session.sd = Some(Value::from(rid)); session.sd = Some(Value::from(rid));
session.au = Arc::new(Auth::Sc(ns, db, sc)); session.au = Arc::new(Auth::Sc(ns, db, sc));
// Create the authentication token // Check the authentication token
match encode(&*HEADER, &val, &key) { match enc {
// The auth token was created successfully // The auth token was created successfully
Ok(tk) => Ok(tk), Ok(tk) => Ok(tk),
// There was an error creating the token // There was an error creating the token
@ -206,10 +209,15 @@ pub async fn db(
id: Some(user), id: Some(user),
..Claims::default() ..Claims::default()
}; };
// Set the authentication on the session
session.au = Arc::new(Auth::Db(ns, db));
// Create the authentication token // Create the authentication token
match encode(&*HEADER, &val, &key) { let enc = encode(&*HEADER, &val, &key);
// Set the authentication on the session
session.tk = Some(val.into());
session.ns = Some(ns.to_owned());
session.db = Some(db.to_owned());
session.au = Arc::new(Auth::Db(ns, db));
// Check the authentication token
match enc {
// The auth token was created successfully // The auth token was created successfully
Ok(tk) => Ok(tk), Ok(tk) => Ok(tk),
// There was an error creating the token // There was an error creating the token
@ -255,10 +263,14 @@ pub async fn ns(
id: Some(user), id: Some(user),
..Claims::default() ..Claims::default()
}; };
// Set the authentication on the session
session.au = Arc::new(Auth::Ns(ns));
// Create the authentication token // Create the authentication token
match encode(&*HEADER, &val, &key) { let enc = encode(&*HEADER, &val, &key);
// Set the authentication on the session
session.tk = Some(val.into());
session.ns = Some(ns.to_owned());
session.au = Arc::new(Auth::Ns(ns));
// Check the authentication token
match enc {
// The auth token was created successfully // The auth token was created successfully
Ok(tk) => Ok(tk), Ok(tk) => Ok(tk),
// There was an error creating the token // There was an error creating the token

View file

@ -79,14 +79,17 @@ pub async fn sc(
id: Some(rid.to_raw()), id: Some(rid.to_raw()),
..Claims::default() ..Claims::default()
}; };
// Create the authentication token
let enc = encode(&*HEADER, &val, &key);
// Set the authentication on the session // Set the authentication on the session
session.tk = Some(val.into());
session.ns = Some(ns.to_owned()); session.ns = Some(ns.to_owned());
session.db = Some(db.to_owned()); session.db = Some(db.to_owned());
session.sc = Some(sc.to_owned()); session.sc = Some(sc.to_owned());
session.sd = Some(Value::from(rid)); session.sd = Some(Value::from(rid));
session.au = Arc::new(Auth::Sc(ns, db, sc)); session.au = Arc::new(Auth::Sc(ns, db, sc));
// Create the authentication token // Create the authentication token
match encode(&*HEADER, &val, &key) { match enc {
// The auth token was created successfully // The auth token was created successfully
Ok(tk) => Ok(tk), Ok(tk) => Ok(tk),
// There was an error creating the token // There was an error creating the token

View file

@ -1,6 +1,8 @@
use jsonwebtoken::{Algorithm, Header}; use jsonwebtoken::{Algorithm, Header};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use surrealdb::sql::Object;
use surrealdb::sql::Value;
pub static HEADER: Lazy<Header> = Lazy::new(|| Header::new(Algorithm::HS512)); pub static HEADER: Lazy<Header> = Lazy::new(|| Header::new(Algorithm::HS512));
@ -36,3 +38,37 @@ pub struct Claims {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>, pub id: Option<String>,
} }
impl From<Claims> for Value {
fn from(v: Claims) -> Value {
// Set default value
let mut out = Object::default();
// Add default fields
out.insert("iat".to_string(), v.iat.into());
out.insert("nbf".to_string(), v.nbf.into());
out.insert("exp".to_string(), v.exp.into());
out.insert("iss".to_string(), v.iss.into());
// Add NS field if set
if let Some(ns) = v.ns {
out.insert("NS".to_string(), ns.into());
}
// Add DB field if set
if let Some(db) = v.db {
out.insert("DB".to_string(), db.into());
}
// Add SC field if set
if let Some(sc) = v.sc {
out.insert("SC".to_string(), sc.into());
}
// Add TK field if set
if let Some(tk) = v.tk {
out.insert("TK".to_string(), tk.into());
}
// Add NS field if set
if let Some(id) = v.id {
out.insert("ID".to_string(), id.into());
}
// Return value
out.into()
}
}

View file

@ -156,6 +156,8 @@ pub async fn token(session: &mut Session, auth: String) -> Result<(), Error> {
let kvs = DB.get().unwrap(); let kvs = DB.get().unwrap();
// Decode the token without verifying // Decode the token without verifying
let token = decode::<Claims>(auth, &KEY, &DUD)?; let token = decode::<Claims>(auth, &KEY, &DUD)?;
// Parse the token and catch any errors
let value = super::parse::parse(auth)?;
// Check the token authentication claims // Check the token authentication claims
match token.claims { match token.claims {
// Check if this is scope token authentication // Check if this is scope token authentication
@ -181,6 +183,7 @@ pub async fn token(session: &mut Session, auth: String) -> Result<(), Error> {
// Log the success // Log the success
debug!(target: LOG, "Authenticated to scope `{}` with token `{}`", sc, tk); debug!(target: LOG, "Authenticated to scope `{}` with token `{}`", sc, tk);
// Set the session // Set the session
session.tk = Some(value);
session.ns = Some(ns.to_owned()); session.ns = Some(ns.to_owned());
session.db = Some(db.to_owned()); session.db = Some(db.to_owned());
session.sc = Some(sc.to_owned()); session.sc = Some(sc.to_owned());
@ -210,6 +213,7 @@ pub async fn token(session: &mut Session, auth: String) -> Result<(), Error> {
// Log the success // Log the success
debug!(target: LOG, "Authenticated to scope `{}`", sc); debug!(target: LOG, "Authenticated to scope `{}`", sc);
// Set the session // Set the session
session.tk = Some(value);
session.ns = Some(ns.to_owned()); session.ns = Some(ns.to_owned());
session.db = Some(db.to_owned()); session.db = Some(db.to_owned());
session.sc = Some(sc.to_owned()); session.sc = Some(sc.to_owned());
@ -236,6 +240,7 @@ pub async fn token(session: &mut Session, auth: String) -> Result<(), Error> {
// Log the success // Log the success
debug!(target: LOG, "Authenticated to database `{}` with token `{}`", db, tk); debug!(target: LOG, "Authenticated to database `{}` with token `{}`", db, tk);
// Set the session // Set the session
session.tk = Some(value);
session.ns = Some(ns.to_owned()); session.ns = Some(ns.to_owned());
session.db = Some(db.to_owned()); session.db = Some(db.to_owned());
session.au = Arc::new(Auth::Db(ns, db)); session.au = Arc::new(Auth::Db(ns, db));
@ -260,6 +265,7 @@ pub async fn token(session: &mut Session, auth: String) -> Result<(), Error> {
// Log the success // Log the success
debug!(target: LOG, "Authenticated to database `{}` with login `{}`", db, id); debug!(target: LOG, "Authenticated to database `{}` with login `{}`", db, id);
// Set the session // Set the session
session.tk = Some(value);
session.ns = Some(ns.to_owned()); session.ns = Some(ns.to_owned());
session.db = Some(db.to_owned()); session.db = Some(db.to_owned());
session.au = Arc::new(Auth::Db(ns, db)); session.au = Arc::new(Auth::Db(ns, db));
@ -283,6 +289,7 @@ pub async fn token(session: &mut Session, auth: String) -> Result<(), Error> {
// Log the success // Log the success
trace!(target: LOG, "Authenticated to namespace `{}` with token `{}`", ns, tk); trace!(target: LOG, "Authenticated to namespace `{}` with token `{}`", ns, tk);
// Set the session // Set the session
session.tk = Some(value);
session.ns = Some(ns.to_owned()); session.ns = Some(ns.to_owned());
session.au = Arc::new(Auth::Ns(ns)); session.au = Arc::new(Auth::Ns(ns));
return Ok(()); return Ok(());
@ -305,6 +312,7 @@ pub async fn token(session: &mut Session, auth: String) -> Result<(), Error> {
// Log the success // Log the success
trace!(target: LOG, "Authenticated to namespace `{}` with login `{}`", ns, id); trace!(target: LOG, "Authenticated to namespace `{}` with login `{}`", ns, id);
// Set the session // Set the session
session.tk = Some(value);
session.ns = Some(ns.to_owned()); session.ns = Some(ns.to_owned());
session.au = Arc::new(Auth::Ns(ns)); session.au = Arc::new(Auth::Ns(ns));
return Ok(()); return Ok(());