surrealdb_core/iam/
signin.rs

1use super::access::{
2	authenticate_generic, authenticate_record, create_refresh_token_record,
3	revoke_refresh_token_record,
4};
5use super::verify::{verify_db_creds, verify_ns_creds, verify_root_creds};
6use super::{Actor, Level, Role};
7use crate::cnf::{INSECURE_FORWARD_ACCESS_ERRORS, SERVER_NAME};
8use crate::dbs::capabilities::ExperimentalTarget;
9use crate::dbs::Session;
10use crate::err::Error;
11use crate::iam::issue::{config, expiration};
12use crate::iam::token::{Claims, HEADER};
13use crate::iam::Auth;
14use crate::kvs::{Datastore, LockType::*, TransactionType::*};
15use crate::sql::statements::{access, AccessGrant, DefineAccessStatement};
16use crate::sql::{access_type, AccessType, Datetime, Object, Value};
17use chrono::Utc;
18use jsonwebtoken::{encode, EncodingKey, Header};
19use md5::Digest;
20use revision::revisioned;
21use serde::{Deserialize, Serialize};
22use sha2::Sha256;
23use std::str::FromStr;
24use std::sync::Arc;
25use subtle::ConstantTimeEq;
26use uuid::Uuid;
27
28#[revisioned(revision = 1)]
29#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
30#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
31#[non_exhaustive]
32pub struct SigninData {
33	pub token: String,
34	pub refresh: Option<String>,
35}
36
37impl From<SigninData> for Value {
38	fn from(v: SigninData) -> Value {
39		let mut out = Object::default();
40		out.insert("token".to_string(), v.token.into());
41		if let Some(refresh) = v.refresh {
42			out.insert("refresh".to_string(), refresh.into());
43		}
44		out.into()
45	}
46}
47
48pub async fn signin(
49	kvs: &Datastore,
50	session: &mut Session,
51	vars: Object,
52) -> Result<SigninData, Error> {
53	// Check vars contains only computed values
54	vars.validate_computed()?;
55	// Parse the specified variables
56	let ns = vars.get("NS").or_else(|| vars.get("ns"));
57	let db = vars.get("DB").or_else(|| vars.get("db"));
58	let ac = vars.get("AC").or_else(|| vars.get("ac"));
59	// Check if the parameters exist
60	match (ns, db, ac) {
61		// DB signin with access method
62		(Some(ns), Some(db), Some(ac)) => {
63			// Process the provided values
64			let ns = ns.to_raw_string();
65			let db = db.to_raw_string();
66			let ac = ac.to_raw_string();
67			// Attempt to signin using specified access method
68			super::signin::db_access(kvs, session, ns, db, ac, vars).await
69		}
70		// DB signin with user credentials
71		(Some(ns), Some(db), None) => {
72			// Get the provided user and pass
73			let user = vars.get("user");
74			let pass = vars.get("pass");
75			// Validate the user and pass
76			match (user, pass) {
77				// There is a username and password
78				(Some(user), Some(pass)) => {
79					// Process the provided values
80					let ns = ns.to_raw_string();
81					let db = db.to_raw_string();
82					let user = user.to_raw_string();
83					let pass = pass.to_raw_string();
84					// Attempt to signin to database
85					super::signin::db_user(kvs, session, ns, db, user, pass).await
86				}
87				_ => Err(Error::MissingUserOrPass),
88			}
89		}
90		// NS signin with access method
91		(Some(ns), None, Some(ac)) => {
92			// Process the provided values
93			let ns = ns.to_raw_string();
94			let ac = ac.to_raw_string();
95			// Attempt to signin using specified access method
96			super::signin::ns_access(kvs, session, ns, ac, vars).await
97		}
98		// NS signin with user credentials
99		(Some(ns), None, None) => {
100			// Get the provided user and pass
101			let user = vars.get("user");
102			let pass = vars.get("pass");
103			// Validate the user and pass
104			match (user, pass) {
105				// There is a username and password
106				(Some(user), Some(pass)) => {
107					// Process the provided values
108					let ns = ns.to_raw_string();
109					let user = user.to_raw_string();
110					let pass = pass.to_raw_string();
111					// Attempt to signin to namespace
112					super::signin::ns_user(kvs, session, ns, user, pass).await
113				}
114				_ => Err(Error::MissingUserOrPass),
115			}
116		}
117		// ROOT signin with user credentials
118		(None, None, None) => {
119			// Get the provided user and pass
120			let user = vars.get("user");
121			let pass = vars.get("pass");
122			// Validate the user and pass
123			match (user, pass) {
124				// There is a username and password
125				(Some(user), Some(pass)) => {
126					// Process the provided values
127					let user = user.to_raw_string();
128					let pass = pass.to_raw_string();
129					// Attempt to signin to root
130					super::signin::root_user(kvs, session, user, pass).await
131				}
132				_ => Err(Error::MissingUserOrPass),
133			}
134		}
135		_ => Err(Error::NoSigninTarget),
136	}
137}
138
139pub async fn db_access(
140	kvs: &Datastore,
141	session: &mut Session,
142	ns: String,
143	db: String,
144	ac: String,
145	vars: Object,
146) -> Result<SigninData, Error> {
147	// Create a new readonly transaction
148	let tx = kvs.transaction(Read, Optimistic).await?;
149	// Fetch the specified access method from storage
150	let access = tx.get_db_access(&ns, &db, &ac).await;
151	// Ensure that the transaction is cancelled
152	tx.cancel().await?;
153	// Check the provided access method exists
154	match access {
155		Ok(av) => {
156			// Check the access method type
157			// All access method types are supported except for JWT
158			// The JWT access method is the one that is internal to SurrealDB
159			// The equivalent of signing in with JWT is to authenticate it
160			match av.kind.clone() {
161				AccessType::Record(at) => {
162					// Check if the record access method supports issuing tokens
163					let iss = match &at.jwt.issue {
164						Some(iss) => iss.clone(),
165						_ => return Err(Error::AccessMethodMismatch),
166					};
167					// Check if a refresh token is defined
168					if let Some(bearer) = &at.bearer {
169						// Check if a refresh token is being used to authenticate
170						if let Some(key) = vars.get("refresh") {
171							// Perform bearer access using the refresh token as the bearer key
172							return signin_bearer(
173								kvs,
174								session,
175								Some(ns),
176								Some(db),
177								av,
178								bearer,
179								key.to_raw_string(),
180							)
181							.await;
182						}
183					};
184					match &at.signin {
185						// This record access allows signin
186						Some(val) => {
187							// Setup the query params
188							let vars = Some(vars.0);
189							// Setup the system session for finding the signin record
190							let mut sess = Session::editor().with_ns(&ns).with_db(&db);
191							sess.ip.clone_from(&session.ip);
192							sess.or.clone_from(&session.or);
193							// Compute the value with the params
194							match kvs.evaluate(val, &sess, vars).await {
195								// The signin value succeeded
196								Ok(val) => {
197									match val.record() {
198										// There is a record returned
199										Some(mut rid) => {
200											// Create the authentication key
201											let key = config(iss.alg, &iss.key)?;
202											// Create the authentication claim
203											let claims = Claims {
204												iss: Some(SERVER_NAME.to_owned()),
205												iat: Some(Utc::now().timestamp()),
206												nbf: Some(Utc::now().timestamp()),
207												exp: expiration(av.duration.token)?,
208												jti: Some(Uuid::new_v4().to_string()),
209												ns: Some(ns.to_owned()),
210												db: Some(db.to_owned()),
211												ac: Some(ac.to_owned()),
212												id: Some(rid.to_raw()),
213												..Claims::default()
214											};
215											// AUTHENTICATE clause
216											if let Some(au) = &av.authenticate {
217												// Setup the system session for finding the signin record
218												let mut sess =
219													Session::editor().with_ns(&ns).with_db(&db);
220												sess.rd = Some(rid.clone().into());
221												sess.tk = Some((&claims).into());
222												sess.ip.clone_from(&session.ip);
223												sess.or.clone_from(&session.or);
224												rid = authenticate_record(kvs, &sess, au).await?;
225											}
226											// Create refresh token if defined for the record access method
227											let refresh = match &at.bearer {
228												Some(_) => {
229													// TODO(gguillemas): Remove this once bearer access is no longer experimental
230													if !kvs.get_capabilities().allows_experimental(
231														&ExperimentalTarget::BearerAccess,
232													) {
233														debug!("Will not create refresh token with disabled bearer access feature");
234														None
235													} else {
236														Some(
237															create_refresh_token_record(
238																kvs,
239																av.name.clone(),
240																&ns,
241																&db,
242																rid.clone(),
243															)
244															.await?,
245														)
246													}
247												}
248												None => None,
249											};
250											// Log the authenticated access method info
251											trace!(
252												"Signing in to database with access method `{}`",
253												ac
254											);
255											// Create the authentication token
256											let enc =
257												encode(&Header::new(iss.alg.into()), &claims, &key);
258											// Set the authentication on the session
259											session.tk = Some((&claims).into());
260											session.ns = Some(ns.to_owned());
261											session.db = Some(db.to_owned());
262											session.ac = Some(ac.to_owned());
263											session.rd = Some(Value::from(rid.to_owned()));
264											session.exp = expiration(av.duration.session)?;
265											session.au = Arc::new(Auth::new(Actor::new(
266												rid.to_string(),
267												Default::default(),
268												Level::Record(ns, db, rid.to_string()),
269											)));
270											// Check the authentication token
271											match enc {
272												// The auth token was created successfully
273												Ok(token) => Ok(SigninData {
274													token,
275													refresh,
276												}),
277												_ => Err(Error::TokenMakingFailed),
278											}
279										}
280										_ => Err(Error::NoRecordFound),
281									}
282								}
283								Err(e) => match e {
284									// If the SIGNIN clause throws a specific error, authentication fails with that error
285									Error::Thrown(_) => Err(e),
286									// If the SIGNIN clause failed due to an unexpected error, be more specific
287									// This allows clients to handle these errors, which may be retryable
288									Error::Tx(_) | Error::TxFailure | Error::TxRetryable => {
289										debug!("Unexpected error found while executing a SIGNIN clause: {e}");
290										Err(Error::UnexpectedAuth)
291									}
292									// Otherwise, return a generic error unless it should be forwarded
293									e => {
294										debug!("Record user signin query failed: {e}");
295										if *INSECURE_FORWARD_ACCESS_ERRORS {
296											Err(e)
297										} else {
298											Err(Error::AccessRecordSigninQueryFailed)
299										}
300									}
301								},
302							}
303						}
304						_ => Err(Error::AccessRecordNoSignin),
305					}
306				}
307				AccessType::Bearer(at) => {
308					// Extract key identifier and key from the provided variables.
309					let key = match vars.get("key") {
310						Some(key) => key.to_raw_string(),
311						None => return Err(Error::AccessBearerMissingKey),
312					};
313
314					signin_bearer(kvs, session, Some(ns), Some(db), av, &at, key).await
315				}
316				_ => Err(Error::AccessMethodMismatch),
317			}
318		}
319		_ => Err(Error::AccessNotFound),
320	}
321}
322
323pub async fn db_user(
324	kvs: &Datastore,
325	session: &mut Session,
326	ns: String,
327	db: String,
328	user: String,
329	pass: String,
330) -> Result<SigninData, Error> {
331	match verify_db_creds(kvs, &ns, &db, &user, &pass).await {
332		Ok(u) => {
333			// Create the authentication key
334			let key = EncodingKey::from_secret(u.code.as_ref());
335			// Create the authentication claim
336			let val = Claims {
337				iss: Some(SERVER_NAME.to_owned()),
338				iat: Some(Utc::now().timestamp()),
339				nbf: Some(Utc::now().timestamp()),
340				exp: expiration(u.duration.token)?,
341				jti: Some(Uuid::new_v4().to_string()),
342				ns: Some(ns.to_owned()),
343				db: Some(db.to_owned()),
344				id: Some(user),
345				..Claims::default()
346			};
347			// Log the authenticated database info
348			trace!("Signing in to database `{ns}/{db}`");
349			// Create the authentication token
350			let enc = encode(&HEADER, &val, &key);
351			// Set the authentication on the session
352			session.tk = Some((&val).into());
353			session.ns = Some(ns.to_owned());
354			session.db = Some(db.to_owned());
355			session.exp = expiration(u.duration.session)?;
356			session.au = Arc::new((&u, Level::Database(ns.to_owned(), db.to_owned())).try_into()?);
357			// Check the authentication token
358			match enc {
359				// The auth token was created successfully
360				Ok(tk) => Ok(SigninData {
361					token: tk,
362					refresh: None,
363				}),
364				_ => Err(Error::TokenMakingFailed),
365			}
366		}
367		// The password did not verify
368		Err(e) => {
369			debug!("Failed to verify signin credentials for user `{user}` in database `{ns}/{db}`: {e}");
370			Err(Error::InvalidAuth)
371		}
372	}
373}
374
375pub async fn ns_access(
376	kvs: &Datastore,
377	session: &mut Session,
378	ns: String,
379	ac: String,
380	vars: Object,
381) -> Result<SigninData, Error> {
382	// Create a new readonly transaction
383	let tx = kvs.transaction(Read, Optimistic).await?;
384	// Fetch the specified access method from storage
385	let access = tx.get_ns_access(&ns, &ac).await;
386	// Ensure that the transaction is cancelled
387	tx.cancel().await?;
388	// Check the provided access method exists
389	match access {
390		Ok(av) => {
391			// Check the access method type
392			match av.kind.clone() {
393				AccessType::Bearer(at) => {
394					// Extract key identifier and key from the provided variables.
395					let key = match vars.get("key") {
396						Some(key) => key.to_raw_string(),
397						None => return Err(Error::AccessBearerMissingKey),
398					};
399
400					signin_bearer(kvs, session, Some(ns), None, av, &at, key).await
401				}
402				_ => Err(Error::AccessMethodMismatch),
403			}
404		}
405		_ => Err(Error::AccessNotFound),
406	}
407}
408
409pub async fn ns_user(
410	kvs: &Datastore,
411	session: &mut Session,
412	ns: String,
413	user: String,
414	pass: String,
415) -> Result<SigninData, Error> {
416	match verify_ns_creds(kvs, &ns, &user, &pass).await {
417		Ok(u) => {
418			// Create the authentication key
419			let key = EncodingKey::from_secret(u.code.as_ref());
420			// Create the authentication claim
421			let val = Claims {
422				iss: Some(SERVER_NAME.to_owned()),
423				iat: Some(Utc::now().timestamp()),
424				nbf: Some(Utc::now().timestamp()),
425				exp: expiration(u.duration.token)?,
426				jti: Some(Uuid::new_v4().to_string()),
427				ns: Some(ns.to_owned()),
428				id: Some(user),
429				..Claims::default()
430			};
431			// Log the authenticated namespace info
432			trace!("Signing in to namespace `{ns}`");
433			// Create the authentication token
434			let enc = encode(&HEADER, &val, &key);
435			// Set the authentication on the session
436			session.tk = Some((&val).into());
437			session.ns = Some(ns.to_owned());
438			session.exp = expiration(u.duration.session)?;
439			session.au = Arc::new((&u, Level::Namespace(ns.to_owned())).try_into()?);
440			// Check the authentication token
441			match enc {
442				// The auth token was created successfully
443				Ok(tk) => Ok(SigninData {
444					token: tk,
445					refresh: None,
446				}),
447				_ => Err(Error::TokenMakingFailed),
448			}
449		}
450		// The password did not verify
451		Err(e) => {
452			debug!(
453				"Failed to verify signin credentials for user `{user}` in namespace `{ns}`: {e}"
454			);
455			Err(Error::InvalidAuth)
456		}
457	}
458}
459
460pub async fn root_user(
461	kvs: &Datastore,
462	session: &mut Session,
463	user: String,
464	pass: String,
465) -> Result<SigninData, Error> {
466	match verify_root_creds(kvs, &user, &pass).await {
467		Ok(u) => {
468			// Create the authentication key
469			let key = EncodingKey::from_secret(u.code.as_ref());
470			// Create the authentication claim
471			let val = Claims {
472				iss: Some(SERVER_NAME.to_owned()),
473				iat: Some(Utc::now().timestamp()),
474				nbf: Some(Utc::now().timestamp()),
475				exp: expiration(u.duration.token)?,
476				jti: Some(Uuid::new_v4().to_string()),
477				id: Some(user),
478				..Claims::default()
479			};
480			// Log the authenticated root info
481			trace!("Signing in as root");
482			// Create the authentication token
483			let enc = encode(&HEADER, &val, &key);
484			// Set the authentication on the session
485			session.tk = Some(val.into());
486			session.exp = expiration(u.duration.session)?;
487			session.au = Arc::new((&u, Level::Root).try_into()?);
488			// Check the authentication token
489			match enc {
490				// The auth token was created successfully
491				Ok(tk) => Ok(SigninData {
492					token: tk,
493					refresh: None,
494				}),
495				_ => Err(Error::TokenMakingFailed),
496			}
497		}
498		// The password did not verify
499		Err(e) => {
500			debug!("Failed to verify signin credentials for user `{user}` in root: {e}");
501			Err(Error::InvalidAuth)
502		}
503	}
504}
505
506pub async fn root_access(
507	kvs: &Datastore,
508	session: &mut Session,
509	ac: String,
510	vars: Object,
511) -> Result<SigninData, Error> {
512	// Create a new readonly transaction
513	let tx = kvs.transaction(Read, Optimistic).await?;
514	// Fetch the specified access method from storage
515	let access = tx.get_root_access(&ac).await;
516	// Ensure that the transaction is cancelled
517	tx.cancel().await?;
518	// Check the provided access method exists
519	match access {
520		Ok(av) => {
521			// Check the access method type
522			match av.kind.clone() {
523				AccessType::Bearer(at) => {
524					// Extract key identifier and key from the provided variables.
525					let key = match vars.get("key") {
526						Some(key) => key.to_raw_string(),
527						None => return Err(Error::AccessBearerMissingKey),
528					};
529
530					signin_bearer(kvs, session, None, None, av, &at, key).await
531				}
532				_ => Err(Error::AccessMethodMismatch),
533			}
534		}
535		_ => Err(Error::AccessNotFound),
536	}
537}
538
539pub async fn signin_bearer(
540	kvs: &Datastore,
541	session: &mut Session,
542	ns: Option<String>,
543	db: Option<String>,
544	av: Arc<DefineAccessStatement>,
545	at: &access_type::BearerAccess,
546	key: String,
547) -> Result<SigninData, Error> {
548	// TODO(gguillemas): Remove this once bearer access is no longer experimental.
549	if !kvs.get_capabilities().allows_experimental(&ExperimentalTarget::BearerAccess) {
550		// Return opaque error to avoid leaking the existence of the feature.
551		debug!("Error attempting to authenticate with disabled bearer access feature");
552		return Err(Error::InvalidAuth);
553	}
554	// Check if the bearer access method supports issuing tokens.
555	let iss = match &at.jwt.issue {
556		Some(iss) => iss.clone(),
557		_ => return Err(Error::AccessMethodMismatch),
558	};
559	// Extract key identifier and key from the provided key.
560	let kid = validate_grant_bearer(&key)?;
561	// Create a new readonly transaction
562	let tx = kvs.transaction(Read, Optimistic).await?;
563	// Fetch the specified access grant from storage
564	let gr = match (&ns, &db) {
565		(Some(ns), Some(db)) => tx.get_db_access_grant(ns, db, &av.name, &kid).await,
566		(Some(ns), None) => tx.get_ns_access_grant(ns, &av.name, &kid).await,
567		(None, None) => tx.get_root_access_grant(&av.name, &kid).await,
568		(None, Some(_)) => return Err(Error::NsEmpty),
569	}
570	.map_err(|e| {
571		debug!("Error retrieving bearer access grant: {e}");
572		// Return opaque error to avoid leaking existence of the grant.
573		Error::InvalidAuth
574	})?;
575	// Ensure that the transaction is cancelled.
576	tx.cancel().await?;
577	// Authenticate bearer key against stored grant.
578	verify_grant_bearer(&gr, key)?;
579	// If the subject of the grant is a system user, get their roles.
580	let roles = if let access::Subject::User(user) = &gr.subject {
581		// Create a new readonly transaction.
582		let tx = kvs.transaction(Read, Optimistic).await?;
583		// Fetch the specified user from storage.
584		let user = match (&ns, &db) {
585			(Some(ns), Some(db)) => tx.get_db_user(ns, db, user).await.map_err(|e| {
586				debug!("Error retrieving user for bearer access to database `{ns}/{db}`: {e}");
587				// Return opaque error to avoid leaking grant subject existence.
588				Error::InvalidAuth
589			}),
590			(Some(ns), None) => tx.get_ns_user(ns, user).await.map_err(|e| {
591				debug!("Error retrieving user for bearer access to namespace `{ns}`: {e}");
592				// Return opaque error to avoid leaking grant subject existence.
593				Error::InvalidAuth
594			}),
595			(None, None) => tx.get_root_user(user).await.map_err(|e| {
596				debug!("Error retrieving user for bearer access to root: {e}");
597				// Return opaque error to avoid leaking grant subject existence.
598				Error::InvalidAuth
599			}),
600			(None, Some(_)) => return Err(Error::NsEmpty),
601		}?;
602		// Ensure that the transaction is cancelled.
603		tx.cancel().await?;
604		user.roles.clone()
605	} else {
606		vec![]
607	};
608	// Create the authentication key.
609	let key = config(iss.alg, &iss.key)?;
610	// Create the authentication claim.
611	let claims = Claims {
612		iss: Some(SERVER_NAME.to_owned()),
613		iat: Some(Utc::now().timestamp()),
614		nbf: Some(Utc::now().timestamp()),
615		exp: expiration(av.duration.token)?,
616		jti: Some(Uuid::new_v4().to_string()),
617		ns: ns.to_owned(),
618		db: db.to_owned(),
619		ac: Some(av.name.to_string()),
620		id: match &gr.subject {
621			access::Subject::User(user) => Some(user.to_raw()),
622			access::Subject::Record(rid) => Some(rid.to_raw()),
623		},
624		roles: match &gr.subject {
625			access::Subject::User(_) => Some(roles.iter().map(|v| v.to_string()).collect()),
626			access::Subject::Record(_) => Default::default(),
627		},
628		..Claims::default()
629	};
630	// AUTHENTICATE clause
631	if let Some(au) = &av.authenticate {
632		// Setup the system session for executing the clause.
633		let mut sess = match (&ns, &db) {
634			(Some(ns), Some(db)) => Session::editor().with_ns(ns).with_db(db),
635			(Some(ns), None) => Session::editor().with_ns(ns),
636			(None, None) => Session::editor(),
637			(None, Some(_)) => return Err(Error::NsEmpty),
638		};
639		sess.tk = Some((&claims).into());
640		sess.ip.clone_from(&session.ip);
641		sess.or.clone_from(&session.or);
642		authenticate_generic(kvs, &sess, au).await?;
643	}
644	// If the bearer grant is a refresh token.
645	let refresh = match at.kind {
646		access_type::BearerAccessType::Refresh => {
647			match &gr.subject {
648				access::Subject::Record(rid) => {
649					if let (Some(ns), Some(db)) = (&ns, &db) {
650						// Revoke the used refresh token.
651						revoke_refresh_token_record(kvs, gr.id.clone(), gr.ac.clone(), ns, db)
652							.await?;
653						// Create a new refresh token to replace it.
654						let refresh =
655							create_refresh_token_record(kvs, gr.ac.clone(), ns, db, rid.clone())
656								.await?;
657						Some(refresh)
658					} else {
659						debug!("Invalid attempt to authenticate as a record without a namespace and database");
660						return Err(Error::InvalidAuth);
661					}
662				}
663				access::Subject::User(_) => {
664					debug!(
665						"Invalid attempt to authenticatea as a system user with a refresh token"
666					);
667					return Err(Error::InvalidAuth);
668				}
669			}
670		}
671		_ => None,
672	};
673	// Log the authenticated access method information.
674	trace!("Signing in to database with bearer access method `{}`", av.name);
675	// Create the authentication token.
676	let enc = encode(&Header::new(iss.alg.into()), &claims, &key);
677	// Set the authentication on the session.
678	session.tk = Some((&claims).into());
679	session.ns = ns.to_owned();
680	session.db = db.to_owned();
681	session.ac = Some(av.name.to_string());
682	session.exp = expiration(av.duration.session)?;
683	match &gr.subject {
684		access::Subject::User(user) => {
685			session.au = Arc::new(Auth::new(Actor::new(
686				user.to_string(),
687				roles.iter().map(Role::try_from).collect::<Result<_, _>>()?,
688				match (ns, db) {
689					(Some(ns), Some(db)) => Level::Database(ns, db),
690					(Some(ns), None) => Level::Namespace(ns),
691					(None, None) => Level::Root,
692					(None, Some(_)) => return Err(Error::NsEmpty),
693				},
694			)));
695		}
696		access::Subject::Record(rid) => {
697			session.au = Arc::new(Auth::new(Actor::new(
698				rid.to_string(),
699				Default::default(),
700				if let (Some(ns), Some(db)) = (ns, db) {
701					Level::Record(ns, db, rid.to_string())
702				} else {
703					debug!("Invalid attempt to authenticate as a record without a namespace and database");
704					return Err(Error::InvalidAuth);
705				},
706			)));
707			session.rd = Some(Value::from(rid.to_owned()));
708		}
709	};
710	// Return the authentication token.
711	match enc {
712		Ok(token) => Ok(SigninData {
713			token,
714			refresh,
715		}),
716		_ => Err(Error::TokenMakingFailed),
717	}
718}
719
720pub fn validate_grant_bearer(key: &str) -> Result<String, Error> {
721	let parts: Vec<&str> = key.split("-").collect();
722	if parts.len() != 4 {
723		return Err(Error::AccessGrantBearerInvalid);
724	}
725	// Check that the prefix type exists.
726	access_type::BearerAccessType::from_str(parts[1])?;
727	// Retrieve the key identifier from the provided key.
728	let kid = parts[2];
729	// Check the length of the key identifier.
730	if kid.len() != access::GRANT_BEARER_ID_LENGTH {
731		return Err(Error::AccessGrantBearerInvalid);
732	};
733	// Retrieve the key from the provided key.
734	let key = parts[3];
735	// Check the length of the key.
736	if key.len() != access::GRANT_BEARER_KEY_LENGTH {
737		return Err(Error::AccessGrantBearerInvalid);
738	};
739
740	Ok(kid.to_string())
741}
742
743pub fn verify_grant_bearer(
744	gr: &Arc<AccessGrant>,
745	key: String,
746) -> Result<&access::GrantBearer, Error> {
747	// Check if the grant is revoked or expired.
748	match (&gr.expiration, &gr.revocation) {
749		(None, None) => {}
750		(Some(exp), None) => {
751			if exp < &Datetime::default() {
752				// Return opaque error to avoid leaking revocation status.
753				debug!("Bearer access grant `{}` for method `{}` is expired", gr.id, gr.ac);
754				return Err(Error::InvalidAuth);
755			}
756		}
757		(_, Some(_)) => {
758			debug!("Bearer access grant `{}` for method `{}` is revoked", gr.id, gr.ac);
759			return Err(Error::InvalidAuth);
760		}
761	}
762	// Check if the provided key matches the bearer key in the grant.
763	// We use time-constant comparison to prevent timing attacks.
764	match &gr.grant {
765		access::Grant::Bearer(bearer) => {
766			// Hash provided signin bearer key.
767			let mut hasher = Sha256::new();
768			hasher.update(key);
769			let hash = hasher.finalize();
770			let hash_hex = format!("{hash:x}");
771			// Compare hashed key to stored bearer key.
772			let signin_key_bytes: &[u8] = hash_hex.as_bytes();
773			let bearer_key_bytes: &[u8] = bearer.key.as_bytes();
774			let ok: bool = bearer_key_bytes.ct_eq(signin_key_bytes).into();
775			if ok {
776				Ok(bearer)
777			} else {
778				debug!("Bearer access grant `{}` for method `{}` is invalid", gr.id, gr.ac);
779				Err(Error::InvalidAuth)
780			}
781		}
782		_ => Err(Error::AccessMethodMismatch),
783	}
784}
785
786#[cfg(test)]
787mod tests {
788	use super::*;
789	use crate::{dbs::Capabilities, iam::Role};
790	use chrono::Duration;
791	use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
792	use regex::Regex;
793	use std::collections::HashMap;
794
795	struct TestLevel {
796		level: &'static str,
797		ns: Option<&'static str>,
798		db: Option<&'static str>,
799	}
800
801	const AVAILABLE_ROLES: [Role; 3] = [Role::Viewer, Role::Editor, Role::Owner];
802
803	#[tokio::test]
804	async fn test_signin_record() {
805		// Test with correct credentials
806		{
807			let ds = Datastore::new("memory").await.unwrap();
808			let sess = Session::owner().with_ns("test").with_db("test");
809			ds.execute(
810				r#"
811				DEFINE ACCESS user ON DATABASE TYPE RECORD
812					SIGNIN (
813						SELECT * FROM user WHERE name = $user AND crypto::argon2::compare(pass, $pass)
814					)
815					SIGNUP (
816						CREATE user CONTENT {
817							name: $user,
818							pass: crypto::argon2::generate($pass)
819						}
820					)
821					DURATION FOR SESSION 2h
822				;
823
824				CREATE user:test CONTENT {
825					name: 'user',
826					pass: crypto::argon2::generate('pass')
827				}
828				"#,
829				&sess,
830				None,
831			)
832			.await
833			.unwrap();
834
835			// Signin with the user
836			let mut sess = Session {
837				ns: Some("test".to_string()),
838				db: Some("test".to_string()),
839				..Default::default()
840			};
841			let mut vars: HashMap<&str, Value> = HashMap::new();
842			vars.insert("user", "user".into());
843			vars.insert("pass", "pass".into());
844			let res = db_access(
845				&ds,
846				&mut sess,
847				"test".to_string(),
848				"test".to_string(),
849				"user".to_string(),
850				vars.into(),
851			)
852			.await;
853
854			assert!(res.is_ok(), "Failed to signin with credentials: {:?}", res);
855			assert_eq!(sess.ns, Some("test".to_string()));
856			assert_eq!(sess.db, Some("test".to_string()));
857			assert_eq!(sess.au.id(), "user:test");
858			assert!(sess.au.is_record());
859			assert_eq!(sess.au.level().ns(), Some("test"));
860			assert_eq!(sess.au.level().db(), Some("test"));
861			assert_eq!(sess.au.level().id(), Some("user:test"));
862			// Record users should not have roles
863			assert!(!sess.au.has_role(Role::Viewer), "Auth user expected to not have Viewer role");
864			assert!(!sess.au.has_role(Role::Editor), "Auth user expected to not have Editor role");
865			assert!(!sess.au.has_role(Role::Owner), "Auth user expected to not have Owner role");
866			// Expiration should match the defined duration
867			let exp = sess.exp.unwrap();
868			// Expiration should match the current time plus session duration with some margin
869			let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
870			let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
871			assert!(
872				exp > min_exp && exp < max_exp,
873				"Session expiration is expected to follow the defined duration"
874			);
875		}
876
877		// Test with incorrect credentials
878		{
879			let ds = Datastore::new("memory").await.unwrap();
880			let sess = Session::owner().with_ns("test").with_db("test");
881			ds.execute(
882				r#"
883				DEFINE ACCESS user ON DATABASE TYPE RECORD
884					SIGNIN (
885						SELECT * FROM user WHERE name = $user AND crypto::argon2::compare(pass, $pass)
886					)
887					SIGNUP (
888						CREATE user CONTENT {
889							name: $user,
890							pass: crypto::argon2::generate($pass)
891						}
892					)
893					DURATION FOR SESSION 2h
894				;
895
896				CREATE user:test CONTENT {
897					name: 'user',
898					pass: crypto::argon2::generate('pass')
899				}
900				"#,
901				&sess,
902				None,
903			)
904			.await
905			.unwrap();
906
907			// Signin with the user
908			let mut sess = Session {
909				ns: Some("test".to_string()),
910				db: Some("test".to_string()),
911				..Default::default()
912			};
913			let mut vars: HashMap<&str, Value> = HashMap::new();
914			vars.insert("user", "user".into());
915			vars.insert("pass", "incorrect".into());
916			let res = db_access(
917				&ds,
918				&mut sess,
919				"test".to_string(),
920				"test".to_string(),
921				"user".to_string(),
922				vars.into(),
923			)
924			.await;
925
926			assert!(res.is_err(), "Unexpected successful signin: {:?}", res);
927		}
928	}
929
930	#[tokio::test]
931	async fn test_signin_record_with_refresh() {
932		// Test without refresh
933		{
934			let ds = Datastore::new("memory").await.unwrap();
935			let sess = Session::owner().with_ns("test").with_db("test");
936			ds.execute(
937				r#"
938				DEFINE ACCESS user ON DATABASE TYPE RECORD
939					SIGNIN (
940						SELECT * FROM user WHERE name = $user AND crypto::argon2::compare(pass, $pass)
941					)
942					DURATION FOR GRANT 1w, FOR SESSION 2h
943				;
944
945				CREATE user:test CONTENT {
946					name: 'user',
947					pass: crypto::argon2::generate('pass')
948				}
949				"#,
950				&sess,
951				None,
952			)
953			.await
954			.unwrap();
955
956			// Signin with the user
957			let mut sess = Session {
958				ns: Some("test".to_string()),
959				db: Some("test".to_string()),
960				..Default::default()
961			};
962			let mut vars: HashMap<&str, Value> = HashMap::new();
963			vars.insert("user", "user".into());
964			vars.insert("pass", "pass".into());
965			let res = db_access(
966				&ds,
967				&mut sess,
968				"test".to_string(),
969				"test".to_string(),
970				"user".to_string(),
971				vars.into(),
972			)
973			.await;
974
975			match res {
976				Ok(data) => {
977					assert!(data.refresh.is_none(), "Refresh token was unexpectedly returned")
978				}
979				Err(e) => panic!("Failed to signin with credentials: {e}"),
980			}
981		}
982		// Test with refresh
983		{
984			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
985				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
986			);
987			let sess = Session::owner().with_ns("test").with_db("test");
988			ds.execute(
989				r#"
990				DEFINE ACCESS user ON DATABASE TYPE RECORD
991					SIGNIN (
992						SELECT * FROM user WHERE name = $user AND crypto::argon2::compare(pass, $pass)
993					)
994					WITH REFRESH
995					DURATION FOR GRANT 1w, FOR SESSION 2h
996				;
997
998				CREATE user:test CONTENT {
999					name: 'user',
1000					pass: crypto::argon2::generate('pass')
1001				}
1002				"#,
1003				&sess,
1004				None,
1005			)
1006			.await
1007			.unwrap();
1008
1009			// Signin with the user
1010			let mut sess = Session {
1011				ns: Some("test".to_string()),
1012				db: Some("test".to_string()),
1013				..Default::default()
1014			};
1015			let mut vars: HashMap<&str, Value> = HashMap::new();
1016			vars.insert("user", "user".into());
1017			vars.insert("pass", "pass".into());
1018			let res = db_access(
1019				&ds,
1020				&mut sess,
1021				"test".to_string(),
1022				"test".to_string(),
1023				"user".to_string(),
1024				vars.into(),
1025			)
1026			.await;
1027
1028			assert!(res.is_ok(), "Failed to signin with credentials: {:?}", res);
1029			let refresh = match res {
1030				Ok(data) => match data.refresh {
1031					Some(refresh) => refresh,
1032					None => panic!("Refresh token was not returned"),
1033				},
1034				Err(e) => panic!("Failed to signin with credentials: {e}"),
1035			};
1036			assert_eq!(sess.ns, Some("test".to_string()));
1037			assert_eq!(sess.db, Some("test".to_string()));
1038			assert_eq!(sess.au.id(), "user:test");
1039			assert!(sess.au.is_record());
1040			assert_eq!(sess.au.level().ns(), Some("test"));
1041			assert_eq!(sess.au.level().db(), Some("test"));
1042			assert_eq!(sess.au.level().id(), Some("user:test"));
1043			// Record users should not have roles
1044			assert!(!sess.au.has_role(Role::Viewer), "Auth user expected to not have Viewer role");
1045			assert!(!sess.au.has_role(Role::Editor), "Auth user expected to not have Editor role");
1046			assert!(!sess.au.has_role(Role::Owner), "Auth user expected to not have Owner role");
1047			// Expiration should match the defined duration
1048			let exp = sess.exp.unwrap();
1049			// Expiration should match the current time plus session duration with some margin
1050			let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
1051			let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
1052			assert!(
1053				exp > min_exp && exp < max_exp,
1054				"Session expiration is expected to follow the defined duration"
1055			);
1056			// Signin with the refresh token
1057			let mut vars: HashMap<&str, Value> = HashMap::new();
1058			vars.insert("refresh", refresh.clone().into());
1059			let res = db_access(
1060				&ds,
1061				&mut sess,
1062				"test".to_string(),
1063				"test".to_string(),
1064				"user".to_string(),
1065				vars.into(),
1066			)
1067			.await;
1068			// Authentication should be identical as with user credentials
1069			match res {
1070				Ok(data) => match data.refresh {
1071					Some(new_refresh) => assert!(
1072						new_refresh != refresh,
1073						"New refresh token is identical to used one"
1074					),
1075					None => panic!("Refresh token was not returned"),
1076				},
1077				Err(e) => panic!("Failed to signin with credentials: {e}"),
1078			};
1079			assert_eq!(sess.ns, Some("test".to_string()));
1080			assert_eq!(sess.db, Some("test".to_string()));
1081			assert_eq!(sess.au.id(), "user:test");
1082			assert!(sess.au.is_record());
1083			assert_eq!(sess.au.level().ns(), Some("test"));
1084			assert_eq!(sess.au.level().db(), Some("test"));
1085			assert_eq!(sess.au.level().id(), Some("user:test"));
1086			// Record users should not have roles
1087			assert!(!sess.au.has_role(Role::Viewer), "Auth user expected to not have Viewer role");
1088			assert!(!sess.au.has_role(Role::Editor), "Auth user expected to not have Editor role");
1089			assert!(!sess.au.has_role(Role::Owner), "Auth user expected to not have Owner role");
1090			// Expiration should match the defined duration
1091			let exp = sess.exp.unwrap();
1092			// Expiration should match the current time plus session duration with some margin
1093			let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
1094			let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
1095			assert!(
1096				exp > min_exp && exp < max_exp,
1097				"Session expiration is expected to follow the defined duration"
1098			);
1099			// Attempt to sign in with the original refresh token
1100			let mut vars: HashMap<&str, Value> = HashMap::new();
1101			vars.insert("refresh", refresh.into());
1102			let res = db_access(
1103				&ds,
1104				&mut sess,
1105				"test".to_string(),
1106				"test".to_string(),
1107				"user".to_string(),
1108				vars.into(),
1109			)
1110			.await;
1111			match res {
1112				Ok(data) => panic!("Unexpected successful signin: {:?}", data),
1113				Err(Error::InvalidAuth) => {} // ok
1114				Err(e) => panic!("Expected InvalidAuth, but got: {e}"),
1115			}
1116		}
1117		// Test with expired refresh
1118		{
1119			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
1120				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
1121			);
1122			let sess = Session::owner().with_ns("test").with_db("test");
1123			ds.execute(
1124				r#"
1125				DEFINE ACCESS user ON DATABASE TYPE RECORD
1126					SIGNIN (
1127						SELECT * FROM user WHERE name = $user AND crypto::argon2::compare(pass, $pass)
1128					)
1129					WITH REFRESH
1130					DURATION FOR GRANT 1s, FOR SESSION 2h
1131				;
1132
1133				CREATE user:test CONTENT {
1134					name: 'user',
1135					pass: crypto::argon2::generate('pass')
1136				}
1137				"#,
1138				&sess,
1139				None,
1140			)
1141			.await
1142			.unwrap();
1143
1144			// Signin with the user
1145			let mut sess = Session {
1146				ns: Some("test".to_string()),
1147				db: Some("test".to_string()),
1148				..Default::default()
1149			};
1150			let mut vars: HashMap<&str, Value> = HashMap::new();
1151			vars.insert("user", "user".into());
1152			vars.insert("pass", "pass".into());
1153			let res = db_access(
1154				&ds,
1155				&mut sess,
1156				"test".to_string(),
1157				"test".to_string(),
1158				"user".to_string(),
1159				vars.into(),
1160			)
1161			.await;
1162			let refresh = match res {
1163				Ok(data) => match data.refresh {
1164					Some(refresh) => refresh,
1165					None => panic!("Refresh token was not returned"),
1166				},
1167				Err(e) => panic!("Failed to signin with credentials: {e}"),
1168			};
1169			// Wait for the refresh token to expire
1170			std::thread::sleep(Duration::seconds(2).to_std().unwrap());
1171			// Signin with the refresh token
1172			let mut vars: HashMap<&str, Value> = HashMap::new();
1173			vars.insert("refresh", refresh.clone().into());
1174			let res = db_access(
1175				&ds,
1176				&mut sess,
1177				"test".to_string(),
1178				"test".to_string(),
1179				"user".to_string(),
1180				vars.into(),
1181			)
1182			.await;
1183			// Should fail due to the refresh token being expired
1184			match res {
1185				Ok(data) => panic!("Unexpected successful signin: {:?}", data),
1186				Err(Error::InvalidAuth) => {} // ok
1187				Err(e) => panic!("Expected InvalidAuth, but got: {e}"),
1188			}
1189		}
1190		// Test that only the hash of the refresh token is stored
1191		{
1192			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
1193				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
1194			);
1195			let sess = Session::owner().with_ns("test").with_db("test");
1196			ds.execute(
1197				r#"
1198				DEFINE ACCESS user ON DATABASE TYPE RECORD
1199					SIGNIN (
1200						SELECT * FROM user WHERE name = $user AND crypto::argon2::compare(pass, $pass)
1201					)
1202					WITH REFRESH
1203					DURATION FOR GRANT 1w, FOR SESSION 2h
1204				;
1205
1206				CREATE user:test CONTENT {
1207					name: 'user',
1208					pass: crypto::argon2::generate('pass')
1209				}
1210				"#,
1211				&sess,
1212				None,
1213			)
1214			.await
1215			.unwrap();
1216
1217			// Signin with the user
1218			let mut sess = Session {
1219				ns: Some("test".to_string()),
1220				db: Some("test".to_string()),
1221				..Default::default()
1222			};
1223			let mut vars: HashMap<&str, Value> = HashMap::new();
1224			vars.insert("user", "user".into());
1225			vars.insert("pass", "pass".into());
1226			let res = db_access(
1227				&ds,
1228				&mut sess,
1229				"test".to_string(),
1230				"test".to_string(),
1231				"user".to_string(),
1232				vars.into(),
1233			)
1234			.await;
1235
1236			assert!(res.is_ok(), "Failed to signin with credentials: {:?}", res);
1237			let refresh = match res {
1238				Ok(data) => match data.refresh {
1239					Some(refresh) => refresh,
1240					None => panic!("Refresh token was not returned"),
1241				},
1242				Err(e) => panic!("Failed to signin with credentials: {e}"),
1243			};
1244
1245			// Extract grant identifier from refresh token
1246			let id = refresh.split("-").collect::<Vec<&str>>()[2];
1247
1248			// Test that returned refresh token is in plain text
1249			let ok = Regex::new(r"surreal-refresh-[a-zA-Z0-9]{12}-[a-zA-Z0-9]{24}").unwrap();
1250			assert!(ok.is_match(&refresh), "Output '{}' doesn't match regex '{}'", refresh, ok);
1251
1252			// Get the stored bearer key representing the refresh token
1253			let tx = ds.transaction(Read, Optimistic).await.unwrap().enclose();
1254			let grant = tx.get_db_access_grant("test", "test", "user", id).await.unwrap();
1255			let key = match &grant.grant {
1256				access::Grant::Bearer(grant) => grant.key.clone(),
1257				_ => panic!("Incorrect grant type returned, expected a bearer grant"),
1258			};
1259			tx.cancel().await.unwrap();
1260
1261			// Test that the returned key is a SHA-256 hash
1262			let ok = Regex::new(r"[0-9a-f]{64}").unwrap();
1263			assert!(ok.is_match(&key), "Output '{}' doesn't match regex '{}'", key, ok);
1264		}
1265	}
1266
1267	#[tokio::test]
1268	async fn test_signin_record_with_jwt_issuer() {
1269		// Test with correct credentials
1270		{
1271			let public_key = r#"-----BEGIN PUBLIC KEY-----
1272MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
12734lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u
1274+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh
1275kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ
12760iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg
1277cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc
1278mwIDAQAB
1279-----END PUBLIC KEY-----"#;
1280			let private_key = r#"-----BEGIN PRIVATE KEY-----
1281MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj
1282MzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu
1283NMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ
1284qgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg
1285p2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR
1286ZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi
1287VuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV
1288laAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8
1289sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H
1290mQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY
1291dgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw
1292ta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ
1293DM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T
1294N0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t
12950l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv
1296t8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU
1297AhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk
129848RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL
1299DY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK
1300xt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA
1301mNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh
13022bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz
1303et6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr
1304VBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD
1305TQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc
1306dn/RsYEONbwQSjIfMPkvxF+8HQ==
1307-----END PRIVATE KEY-----"#;
1308			let ds = Datastore::new("memory").await.unwrap();
1309			let sess = Session::owner().with_ns("test").with_db("test");
1310			ds.execute(
1311				&format!(
1312					r#"
1313				DEFINE ACCESS user ON DATABASE TYPE RECORD
1314					SIGNIN (
1315						SELECT * FROM user WHERE name = $user AND crypto::argon2::compare(pass, $pass)
1316					)
1317					SIGNUP (
1318						CREATE user CONTENT {{
1319							name: $user,
1320							pass: crypto::argon2::generate($pass)
1321						}}
1322					)
1323				    WITH JWT ALGORITHM RS256 KEY '{public_key}'
1324				        WITH ISSUER KEY '{private_key}'
1325					DURATION FOR SESSION 2h, FOR TOKEN 15m
1326				;
1327
1328				CREATE user:test CONTENT {{
1329					name: 'user',
1330					pass: crypto::argon2::generate('pass')
1331				}}
1332				"#
1333				),
1334				&sess,
1335				None,
1336			)
1337			.await
1338			.unwrap();
1339
1340			// Signin with the user
1341			let mut sess = Session {
1342				ns: Some("test".to_string()),
1343				db: Some("test".to_string()),
1344				..Default::default()
1345			};
1346			let mut vars: HashMap<&str, Value> = HashMap::new();
1347			vars.insert("user", "user".into());
1348			vars.insert("pass", "pass".into());
1349			let res = db_access(
1350				&ds,
1351				&mut sess,
1352				"test".to_string(),
1353				"test".to_string(),
1354				"user".to_string(),
1355				vars.into(),
1356			)
1357			.await;
1358			assert!(res.is_ok(), "Failed to signin with credentials: {:?}", res);
1359			assert_eq!(sess.ns, Some("test".to_string()));
1360			assert_eq!(sess.db, Some("test".to_string()));
1361			assert_eq!(sess.au.id(), "user:test");
1362			assert!(sess.au.is_record());
1363			assert_eq!(sess.au.level().ns(), Some("test"));
1364			assert_eq!(sess.au.level().db(), Some("test"));
1365			assert_eq!(sess.au.level().id(), Some("user:test"));
1366			// Record users should not have roles
1367			assert!(!sess.au.has_role(Role::Viewer), "Auth user expected to not have Viewer role");
1368			assert!(!sess.au.has_role(Role::Editor), "Auth user expected to not have Editor role");
1369			assert!(!sess.au.has_role(Role::Owner), "Auth user expected to not have Owner role");
1370			// Session expiration should match the defined duration
1371			let exp = sess.exp.unwrap();
1372			// Expiration should match the current time plus session duration with some margin
1373			let min_sess_exp =
1374				(Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
1375			let max_sess_exp =
1376				(Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
1377			assert!(
1378				exp > min_sess_exp && exp < max_sess_exp,
1379				"Session expiration is expected to follow the defined duration"
1380			);
1381
1382			// Decode token and check that it has been issued as intended
1383			if let Ok(sd) = res {
1384				// Check that token can be verified with the defined algorithm
1385				let val = Validation::new(Algorithm::RS256);
1386				// Check that token can be verified with the defined public key
1387				let token_data = decode::<Claims>(
1388					&sd.token,
1389					&DecodingKey::from_rsa_pem(public_key.as_ref()).unwrap(),
1390					&val,
1391				)
1392				.unwrap();
1393				// Check that token has been issued with the defined algorithm
1394				assert_eq!(token_data.header.alg, Algorithm::RS256);
1395				// Check that token expiration matches the defined duration
1396				// Expiration should match the current time plus token duration with some margin
1397				let exp = match token_data.claims.exp {
1398					Some(exp) => exp,
1399					_ => panic!("Token is missing expiration claim"),
1400				};
1401				let min_tk_exp =
1402					(Utc::now() + Duration::minutes(15) - Duration::seconds(10)).timestamp();
1403				let max_tk_exp =
1404					(Utc::now() + Duration::minutes(15) + Duration::seconds(10)).timestamp();
1405				assert!(
1406					exp > min_tk_exp && exp < max_tk_exp,
1407					"Token expiration is expected to follow the defined duration"
1408				);
1409				// Check required token claims
1410				assert_eq!(token_data.claims.ns, Some("test".to_string()));
1411				assert_eq!(token_data.claims.db, Some("test".to_string()));
1412				assert_eq!(token_data.claims.id, Some("user:test".to_string()));
1413				assert_eq!(token_data.claims.ac, Some("user".to_string()));
1414			} else {
1415				panic!("Token could not be extracted from result")
1416			}
1417		}
1418	}
1419
1420	#[tokio::test]
1421	async fn test_signin_user() {
1422		#[derive(Debug)]
1423		struct TestCase {
1424			title: &'static str,
1425			password: &'static str,
1426			roles: Vec<Role>,
1427			token_expiration: Option<Duration>,
1428			session_expiration: Option<Duration>,
1429			expect_ok: bool,
1430		}
1431
1432		let test_cases = vec![
1433			TestCase {
1434				title: "without roles or expiration",
1435				password: "pass",
1436				roles: vec![Role::Viewer],
1437				token_expiration: None,
1438				session_expiration: None,
1439				expect_ok: true,
1440			},
1441			TestCase {
1442				title: "with roles and expiration",
1443				password: "pass",
1444				roles: vec![Role::Editor, Role::Owner],
1445				token_expiration: Some(Duration::days(365)),
1446				session_expiration: Some(Duration::days(1)),
1447				expect_ok: true,
1448			},
1449			TestCase {
1450				title: "with invalid password",
1451				password: "invalid",
1452				roles: vec![],
1453				token_expiration: None,
1454				session_expiration: None,
1455				expect_ok: false,
1456			},
1457		];
1458
1459		let test_levels = vec![
1460			TestLevel {
1461				level: "ROOT",
1462				ns: None,
1463				db: None,
1464			},
1465			TestLevel {
1466				level: "NS",
1467				ns: Some("test"),
1468				db: None,
1469			},
1470			TestLevel {
1471				level: "DB",
1472				ns: Some("test"),
1473				db: Some("test"),
1474			},
1475		];
1476
1477		for level in &test_levels {
1478			for case in &test_cases {
1479				println!("Test case: {} level {}", level.level, case.title);
1480				let ds = Datastore::new("memory").await.unwrap();
1481				let sess = Session::owner().with_ns("test").with_db("test");
1482
1483				let roles_clause = if case.roles.is_empty() {
1484					String::new()
1485				} else {
1486					let roles: Vec<&str> = case
1487						.roles
1488						.iter()
1489						.map(|r| match r {
1490							Role::Viewer => "VIEWER",
1491							Role::Editor => "EDITOR",
1492							Role::Owner => "OWNER",
1493						})
1494						.collect();
1495					format!("ROLES {}", roles.join(", "))
1496				};
1497
1498				let mut duration_clause = String::new();
1499				if case.token_expiration.is_some() || case.session_expiration.is_some() {
1500					duration_clause = "DURATION".to_owned()
1501				}
1502				if let Some(duration) = case.token_expiration {
1503					duration_clause =
1504						format!("{} FOR TOKEN {}s", duration_clause, duration.num_seconds())
1505				}
1506				if let Some(duration) = case.session_expiration {
1507					duration_clause =
1508						format!("{} FOR SESSION {}s", duration_clause, duration.num_seconds())
1509				}
1510
1511				let define_user_query = format!(
1512					"DEFINE USER user ON {} PASSWORD 'pass' {} {}",
1513					level.level, roles_clause, duration_clause,
1514				);
1515
1516				ds.execute(&define_user_query, &sess, None).await.unwrap();
1517
1518				let mut sess = Session {
1519					ns: level.ns.map(String::from),
1520					db: level.db.map(String::from),
1521					..Default::default()
1522				};
1523
1524				let res = match level.level {
1525					"ROOT" => {
1526						root_user(&ds, &mut sess, "user".to_string(), case.password.to_string())
1527							.await
1528					}
1529					"NS" => {
1530						ns_user(
1531							&ds,
1532							&mut sess,
1533							level.ns.unwrap().to_string(),
1534							"user".to_string(),
1535							case.password.to_string(),
1536						)
1537						.await
1538					}
1539					"DB" => {
1540						db_user(
1541							&ds,
1542							&mut sess,
1543							level.ns.unwrap().to_string(),
1544							level.db.unwrap().to_string(),
1545							"user".to_string(),
1546							case.password.to_string(),
1547						)
1548						.await
1549					}
1550					_ => panic!("Unsupported level"),
1551				};
1552
1553				if case.expect_ok {
1554					assert!(res.is_ok(), "Failed to signin: {:?}", res);
1555					assert_eq!(sess.ns, level.ns.map(|s| s.to_string()));
1556					assert_eq!(sess.db, level.db.map(|s| s.to_string()));
1557					assert_eq!(sess.au.level().ns(), level.ns);
1558					assert_eq!(sess.au.level().db(), level.db);
1559					assert_eq!(sess.au.id(), "user");
1560
1561					// Check auth level
1562					match level.level {
1563						"ROOT" => assert!(sess.au.is_root()),
1564						"NS" => assert!(sess.au.is_ns()),
1565						"DB" => assert!(sess.au.is_db()),
1566						_ => panic!("Unsupported level"),
1567					}
1568
1569					// Check roles
1570					for role in AVAILABLE_ROLES {
1571						let has_role = sess.au.has_role(role);
1572						let should_have_role = case.roles.contains(&role);
1573						assert_eq!(has_role, should_have_role, "Role {:?} check failed", role);
1574					}
1575
1576					// Check session expiration
1577					if let Some(exp_duration) = case.session_expiration {
1578						let exp = sess.exp.unwrap();
1579						let min_exp =
1580							(Utc::now() + exp_duration - Duration::seconds(10)).timestamp();
1581						let max_exp =
1582							(Utc::now() + exp_duration + Duration::seconds(10)).timestamp();
1583						assert!(
1584							exp > min_exp && exp < max_exp,
1585							"Session expiration is expected to match the defined duration"
1586						);
1587					} else {
1588						assert_eq!(sess.exp, None, "Session expiration is expected to be None");
1589					}
1590
1591					// Check issued token
1592					if let Ok(sd) = res {
1593						// Decode token without validation
1594						let token_data =
1595							decode::<Claims>(&sd.token, &DecodingKey::from_secret(&[]), &{
1596								let mut validation =
1597									Validation::new(jsonwebtoken::Algorithm::HS256);
1598								validation.insecure_disable_signature_validation();
1599								validation.validate_nbf = false;
1600								validation.validate_exp = false;
1601								validation
1602							})
1603							.unwrap();
1604
1605						// Check session expiration
1606						if let Some(exp_duration) = case.token_expiration {
1607							let exp = match token_data.claims.exp {
1608								Some(exp) => exp,
1609								_ => panic!("Token is missing expiration claim"),
1610							};
1611							let min_exp =
1612								(Utc::now() + exp_duration - Duration::seconds(10)).timestamp();
1613							let max_exp =
1614								(Utc::now() + exp_duration + Duration::seconds(10)).timestamp();
1615							assert!(
1616								exp > min_exp && exp < max_exp,
1617								"Session expiration is expected to match the defined duration"
1618							);
1619						} else {
1620							assert_eq!(sess.exp, None, "Session expiration is expected to be None");
1621						}
1622
1623						// Check required token claims
1624						assert_eq!(token_data.claims.ns, level.ns.map(|s| s.to_string()));
1625						assert_eq!(token_data.claims.db, level.db.map(|s| s.to_string()));
1626						assert_eq!(token_data.claims.id, Some("user".to_string()));
1627					} else {
1628						panic!("Token could not be extracted from result")
1629					}
1630				} else {
1631					assert!(res.is_err(), "Unexpected successful signin: {:?}", res);
1632				}
1633			}
1634		}
1635	}
1636
1637	#[tokio::test]
1638	async fn test_signin_record_and_authenticate_clause() {
1639		// Test with correct credentials
1640		{
1641			let ds = Datastore::new("memory").await.unwrap();
1642			let sess = Session::owner().with_ns("test").with_db("test");
1643			ds.execute(
1644				r#"
1645				DEFINE ACCESS user ON DATABASE TYPE RECORD
1646					SIGNIN (
1647						SELECT * FROM type::thing('user', $id)
1648					)
1649					AUTHENTICATE (
1650						-- Simple example increasing the record identifier by one
1651					    SELECT * FROM type::thing('user', record::id($auth) + 1)
1652					)
1653					DURATION FOR SESSION 2h
1654				;
1655
1656				CREATE user:1, user:2;
1657				"#,
1658				&sess,
1659				None,
1660			)
1661			.await
1662			.unwrap();
1663
1664			// Signin with the user
1665			let mut sess = Session {
1666				ns: Some("test".to_string()),
1667				db: Some("test".to_string()),
1668				..Default::default()
1669			};
1670			let mut vars: HashMap<&str, Value> = HashMap::new();
1671			vars.insert("id", 1.into());
1672			let res = db_access(
1673				&ds,
1674				&mut sess,
1675				"test".to_string(),
1676				"test".to_string(),
1677				"user".to_string(),
1678				vars.into(),
1679			)
1680			.await;
1681
1682			assert!(res.is_ok(), "Failed to signin with credentials: {:?}", res);
1683			assert_eq!(sess.ns, Some("test".to_string()));
1684			assert_eq!(sess.db, Some("test".to_string()));
1685			assert_eq!(sess.ac, Some("user".to_string()));
1686			assert_eq!(sess.au.id(), "user:2");
1687			assert!(sess.au.is_record());
1688			assert_eq!(sess.au.level().ns(), Some("test"));
1689			assert_eq!(sess.au.level().db(), Some("test"));
1690			assert_eq!(sess.au.level().id(), Some("user:2"));
1691			// Record users should not have roles
1692			assert!(!sess.au.has_role(Role::Viewer), "Auth user expected to not have Viewer role");
1693			assert!(!sess.au.has_role(Role::Editor), "Auth user expected to not have Editor role");
1694			assert!(!sess.au.has_role(Role::Owner), "Auth user expected to not have Owner role");
1695			// Expiration should match the defined duration
1696			let exp = sess.exp.unwrap();
1697			// Expiration should match the current time plus session duration with some margin
1698			let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
1699			let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
1700			assert!(
1701				exp > min_exp && exp < max_exp,
1702				"Session expiration is expected to follow the defined duration"
1703			);
1704		}
1705
1706		// Test with correct credentials and "realistic" scenario
1707		{
1708			let ds = Datastore::new("memory").await.unwrap();
1709			let sess = Session::owner().with_ns("test").with_db("test");
1710			ds.execute(
1711				r#"
1712				DEFINE ACCESS owner ON DATABASE TYPE RECORD
1713					SIGNUP (
1714						-- Allow anyone to sign up as a new company
1715						-- This automatically creates an owner with the same credentials
1716						CREATE company CONTENT {
1717							email: $email,
1718							pass: crypto::argon2::generate($pass),
1719							owner: (CREATE employee CONTENT {
1720								email: $email,
1721								pass: $pass,
1722							}),
1723						}
1724					)
1725					SIGNIN (
1726						-- Allow company owners to log in directly with the company account
1727						SELECT * FROM company WHERE email = $email AND crypto::argon2::compare(pass, $pass)
1728					)
1729					AUTHENTICATE (
1730						-- If logging in with a company account, the session will be authenticated as the first owner
1731						IF record::tb($auth) = "company" {
1732							RETURN SELECT VALUE owner FROM company WHERE id = $auth
1733						}
1734					)
1735					DURATION FOR SESSION 2h
1736				;
1737
1738				CREATE company:1 CONTENT {
1739					email: "info@example.com",
1740					pass: crypto::argon2::generate("company-password"),
1741					owner: employee:2,
1742				};
1743				CREATE employee:1 CONTENT {
1744					email: "member@example.com",
1745					pass: crypto::argon2::generate("member-password"),
1746				};
1747				CREATE employee:2 CONTENT {
1748					email: "owner@example.com",
1749					pass: crypto::argon2::generate("owner-password"),
1750				};
1751				"#,
1752				&sess,
1753				None,
1754			)
1755			.await
1756			.unwrap();
1757
1758			// Signin with the user
1759			let mut sess = Session {
1760				ns: Some("test".to_string()),
1761				db: Some("test".to_string()),
1762				..Default::default()
1763			};
1764			let mut vars: HashMap<&str, Value> = HashMap::new();
1765			vars.insert("email", "info@example.com".into());
1766			vars.insert("pass", "company-password".into());
1767			let res = db_access(
1768				&ds,
1769				&mut sess,
1770				"test".to_string(),
1771				"test".to_string(),
1772				"owner".to_string(),
1773				vars.into(),
1774			)
1775			.await;
1776
1777			assert!(res.is_ok(), "Failed to signin with credentials: {:?}", res);
1778			assert_eq!(sess.ns, Some("test".to_string()));
1779			assert_eq!(sess.db, Some("test".to_string()));
1780			assert_eq!(sess.ac, Some("owner".to_string()));
1781			assert_eq!(sess.au.id(), "employee:2");
1782			assert!(sess.au.is_record());
1783			assert_eq!(sess.au.level().ns(), Some("test"));
1784			assert_eq!(sess.au.level().db(), Some("test"));
1785			assert_eq!(sess.au.level().id(), Some("employee:2"));
1786			// Record users should not have roles
1787			assert!(!sess.au.has_role(Role::Viewer), "Auth user expected to not have Viewer role");
1788			assert!(!sess.au.has_role(Role::Editor), "Auth user expected to not have Editor role");
1789			assert!(!sess.au.has_role(Role::Owner), "Auth user expected to not have Owner role");
1790			// Expiration should match the defined duration
1791			let exp = sess.exp.unwrap();
1792			// Expiration should match the current time plus session duration with some margin
1793			let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
1794			let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
1795			assert!(
1796				exp > min_exp && exp < max_exp,
1797				"Session expiration is expected to follow the defined duration"
1798			);
1799		}
1800
1801		// Test being able to fail authentication
1802		{
1803			let ds = Datastore::new("memory").await.unwrap();
1804			let sess = Session::owner().with_ns("test").with_db("test");
1805			ds.execute(
1806				r#"
1807				DEFINE ACCESS user ON DATABASE TYPE RECORD
1808					SIGNIN (
1809						SELECT * FROM type::thing('user', $id)
1810					)
1811					AUTHENTICATE {
1812					    -- Not just signin, this clause runs across signin, signup and authenticate, which makes it a nice place to centralize logic
1813					    IF !$auth.enabled {
1814							THROW "This user is not enabled";
1815						};
1816
1817						-- Always need to return the user id back, otherwise auth generically fails
1818						RETURN $auth;
1819					}
1820					DURATION FOR SESSION 2h
1821				;
1822
1823				CREATE user:1 SET enabled = false;
1824				"#,
1825				&sess,
1826				None,
1827			)
1828			.await
1829			.unwrap();
1830
1831			// Signin with the user
1832			let mut sess = Session {
1833				ns: Some("test".to_string()),
1834				db: Some("test".to_string()),
1835				..Default::default()
1836			};
1837			let mut vars: HashMap<&str, Value> = HashMap::new();
1838			vars.insert("id", 1.into());
1839			let res = db_access(
1840				&ds,
1841				&mut sess,
1842				"test".to_string(),
1843				"test".to_string(),
1844				"user".to_string(),
1845				vars.into(),
1846			)
1847			.await;
1848
1849			match res {
1850				Err(Error::Thrown(e)) if e == "This user is not enabled" => {} // ok
1851				res => panic!(
1852				    "Expected authentication to failed due to user not being enabled, but instead received: {:?}",
1853					res
1854				),
1855			}
1856		}
1857
1858		// Test AUTHENTICATE clause not returning a value
1859		{
1860			let ds = Datastore::new("memory").await.unwrap();
1861			let sess = Session::owner().with_ns("test").with_db("test");
1862			ds.execute(
1863				r#"
1864				DEFINE ACCESS user ON DATABASE TYPE RECORD
1865					SIGNIN (
1866					   SELECT * FROM type::thing('user', $id)
1867					)
1868					AUTHENTICATE {}
1869					DURATION FOR SESSION 2h
1870				;
1871
1872				CREATE user:1;
1873				"#,
1874				&sess,
1875				None,
1876			)
1877			.await
1878			.unwrap();
1879
1880			// Signin with the user
1881			let mut sess = Session {
1882				ns: Some("test".to_string()),
1883				db: Some("test".to_string()),
1884				..Default::default()
1885			};
1886			let mut vars: HashMap<&str, Value> = HashMap::new();
1887			vars.insert("id", 1.into());
1888			let res = db_access(
1889				&ds,
1890				&mut sess,
1891				"test".to_string(),
1892				"test".to_string(),
1893				"user".to_string(),
1894				vars.into(),
1895			)
1896			.await;
1897
1898			match res {
1899				Err(Error::InvalidAuth) => {} // ok
1900				res => panic!(
1901					"Expected authentication to generally fail, but instead received: {:?}",
1902					res
1903				),
1904			}
1905		}
1906	}
1907
1908	#[tokio::test]
1909	#[ignore = "flaky"]
1910	async fn test_signin_record_transaction_conflict() {
1911		// Test SIGNIN failing due to datastore transaction conflict
1912		{
1913			let ds = Datastore::new("memory").await.unwrap();
1914			let sess = Session::owner().with_ns("test").with_db("test");
1915			ds.execute(
1916				r#"
1917				DEFINE ACCESS user ON DATABASE TYPE RECORD
1918					SIGNIN {
1919						-- Concurrently write to the same document
1920						UPSERT count:1 SET count += 1;
1921						-- Increase the duration of the transaction
1922						sleep(500ms);
1923						-- Continue with authentication
1924						RETURN (SELECT * FROM user WHERE name = $user AND crypto::argon2::compare(pass, $pass))
1925					}
1926					SIGNUP (
1927						CREATE user CONTENT {
1928							name: $user,
1929							pass: crypto::argon2::generate($pass)
1930						}
1931					)
1932					DURATION FOR SESSION 2h
1933				;
1934
1935				CREATE user:test CONTENT {
1936					name: 'user',
1937					pass: crypto::argon2::generate('pass')
1938				}
1939				"#,
1940				&sess,
1941				None,
1942			)
1943			.await
1944			.unwrap();
1945
1946			// Sign in with the user twice at the same time
1947			let mut sess1 = Session {
1948				ns: Some("test".to_string()),
1949				db: Some("test".to_string()),
1950				..Default::default()
1951			};
1952			let mut sess2 = Session {
1953				ns: Some("test".to_string()),
1954				db: Some("test".to_string()),
1955				..Default::default()
1956			};
1957			let mut vars: HashMap<&str, Value> = HashMap::new();
1958			vars.insert("user", "user".into());
1959			vars.insert("pass", "pass".into());
1960
1961			let (res1, res2) = tokio::join!(
1962				db_access(
1963					&ds,
1964					&mut sess1,
1965					"test".to_string(),
1966					"test".to_string(),
1967					"user".to_string(),
1968					vars.clone().into(),
1969				),
1970				db_access(
1971					&ds,
1972					&mut sess2,
1973					"test".to_string(),
1974					"test".to_string(),
1975					"user".to_string(),
1976					vars.into(),
1977				)
1978			);
1979
1980			match (res1, res2) {
1981				(Ok(r1), Ok(r2)) => panic!("Expected authentication to fail in one instance, but instead received: {:?} and {:?}", r1, r2),
1982				(Err(e1), Err(e2)) => panic!("Expected authentication to fail in one instance, but instead received: {:?} and {:?}", e1, e2),
1983				(Err(e1), Ok(_)) => match &e1 {
1984						Error::UnexpectedAuth => {} // ok
1985						e => panic!("Expected authentication to return an UnexpectedAuth error, but insted got: {e}")
1986				}
1987				(Ok(_), Err(e2)) => match &e2 {
1988						Error::UnexpectedAuth => {} // ok
1989						e => panic!("Expected authentication to return an UnexpectedAuth error, but insted got: {e}")
1990				}
1991			}
1992		}
1993
1994		// Test AUTHENTICATE failing due to datastore transaction conflict
1995		{
1996			let ds = Datastore::new("memory").await.unwrap();
1997			let sess = Session::owner().with_ns("test").with_db("test");
1998			ds.execute(
1999				r#"
2000				DEFINE ACCESS user ON DATABASE TYPE RECORD
2001					SIGNIN (
2002						SELECT * FROM type::thing('user', $id)
2003					)
2004					AUTHENTICATE {
2005						-- Concurrently write to the same document
2006						UPSERT count:1 SET count += 1;
2007						-- Increase the duration of the transaction
2008						sleep(500ms);
2009						-- Continue with authentication
2010						$auth.id -- Continue with authentication
2011					}
2012					DURATION FOR SESSION 2h
2013				;
2014
2015				CREATE user:1;
2016				"#,
2017				&sess,
2018				None,
2019			)
2020			.await
2021			.unwrap();
2022
2023			// Sign in with the user twice at the same time
2024			let mut sess1 = Session {
2025				ns: Some("test".to_string()),
2026				db: Some("test".to_string()),
2027				..Default::default()
2028			};
2029			let mut sess2 = Session {
2030				ns: Some("test".to_string()),
2031				db: Some("test".to_string()),
2032				..Default::default()
2033			};
2034			let mut vars: HashMap<&str, Value> = HashMap::new();
2035			vars.insert("id", 1.into());
2036
2037			let (res1, res2) = tokio::join!(
2038				db_access(
2039					&ds,
2040					&mut sess1,
2041					"test".to_string(),
2042					"test".to_string(),
2043					"user".to_string(),
2044					vars.clone().into(),
2045				),
2046				db_access(
2047					&ds,
2048					&mut sess2,
2049					"test".to_string(),
2050					"test".to_string(),
2051					"user".to_string(),
2052					vars.into(),
2053				)
2054			);
2055
2056			match (res1, res2) {
2057				(Ok(r1), Ok(r2)) => panic!("Expected authentication to fail in one instance, but instead received: {:?} and {:?}", r1, r2),
2058				(Err(e1), Err(e2)) => panic!("Expected authentication to fail in one instance, but instead received: {:?} and {:?}", e1, e2),
2059				(Err(e1), Ok(_)) => match &e1 {
2060						Error::UnexpectedAuth => {} // ok
2061						e => panic!("Expected authentication to return an UnexpectedAuth error, but insted got: {e}")
2062				}
2063				(Ok(_), Err(e2)) => match &e2 {
2064						Error::UnexpectedAuth => {} // ok
2065						e => panic!("Expected authentication to return an UnexpectedAuth error, but insted got: {e}")
2066				}
2067			}
2068		}
2069	}
2070
2071	#[tokio::test]
2072	async fn test_signin_bearer_for_user() {
2073		let test_levels = vec![
2074			TestLevel {
2075				level: "ROOT",
2076				ns: None,
2077				db: None,
2078			},
2079			TestLevel {
2080				level: "NS",
2081				ns: Some("test"),
2082				db: None,
2083			},
2084			TestLevel {
2085				level: "DB",
2086				ns: Some("test"),
2087				db: Some("test"),
2088			},
2089		];
2090
2091		let plain_text_regex =
2092			Regex::new("surreal-bearer-[a-zA-Z0-9]{12}-[a-zA-Z0-9]{24}").unwrap();
2093		let sha_256_regex = Regex::new(r"[0-9a-f]{64}").unwrap();
2094
2095		for level in &test_levels {
2096			println!("Test level: {}", level.level);
2097
2098			// Test with correct bearer key
2099			{
2100				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2101					Capabilities::default()
2102						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2103				);
2104				let sess = Session::owner().with_ns("test").with_db("test");
2105				let res = ds
2106					.execute(
2107						&format!(
2108							r#"
2109					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2110						DURATION FOR SESSION 2h
2111					;
2112					DEFINE USER tobie ON {} ROLES EDITOR;
2113					ACCESS api ON {} GRANT FOR USER tobie;
2114					"#,
2115							level.level, level.level, level.level
2116						),
2117						&sess,
2118						None,
2119					)
2120					.await
2121					.unwrap();
2122
2123				// Get the bearer key from grant
2124				let result = if let Ok(res) = &res.last().unwrap().result {
2125					res.clone()
2126				} else {
2127					panic!("Unable to retrieve bearer key grant");
2128				};
2129				let grant = result
2130					.coerce_to_object()
2131					.unwrap()
2132					.get("grant")
2133					.unwrap()
2134					.clone()
2135					.coerce_to_object()
2136					.unwrap();
2137				let key = grant.get("key").unwrap().clone().as_string();
2138
2139				// Sign in with the bearer key
2140				let mut sess = Session {
2141					ns: level.ns.map(String::from),
2142					db: level.db.map(String::from),
2143					..Default::default()
2144				};
2145				let mut vars: HashMap<&str, Value> = HashMap::new();
2146				vars.insert("key", key.into());
2147				let res = match level.level {
2148					"DB" => {
2149						db_access(
2150							&ds,
2151							&mut sess,
2152							level.ns.unwrap().to_string(),
2153							level.db.unwrap().to_string(),
2154							"api".to_string(),
2155							vars.into(),
2156						)
2157						.await
2158					}
2159					"NS" => {
2160						ns_access(
2161							&ds,
2162							&mut sess,
2163							level.ns.unwrap().to_string(),
2164							"api".to_string(),
2165							vars.into(),
2166						)
2167						.await
2168					}
2169					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
2170					_ => panic!("Unsupported level"),
2171				};
2172
2173				assert!(res.is_ok(), "Failed to sign in with bearer key: {:?}", res);
2174				assert_eq!(sess.ns, level.ns.map(|s| s.to_string()));
2175				assert_eq!(sess.db, level.db.map(|s| s.to_string()));
2176
2177				// Check auth level
2178				match level.level {
2179					"ROOT" => assert!(sess.au.is_root()),
2180					"NS" => assert!(sess.au.is_ns()),
2181					"DB" => assert!(sess.au.is_db()),
2182					_ => panic!("Unsupported level"),
2183				}
2184				assert_eq!(sess.au.level().ns(), level.ns);
2185				assert_eq!(sess.au.level().db(), level.db);
2186
2187				// Check roles
2188				assert!(
2189					!sess.au.has_role(Role::Viewer),
2190					"Auth user expected to not have Viewer role"
2191				);
2192				assert!(
2193					// User is defined with this role only
2194					sess.au.has_role(Role::Editor),
2195					"Auth user expected to have Editor role"
2196				);
2197				assert!(
2198					!sess.au.has_role(Role::Owner),
2199					"Auth user expected to not have Owner role"
2200				);
2201
2202				// Check expiration
2203				let exp = sess.exp.unwrap();
2204				let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
2205				let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
2206				assert!(
2207					exp > min_exp && exp < max_exp,
2208					"Session expiration is expected to match the defined duration",
2209				);
2210			}
2211
2212			// Test with correct bearer key and AUTHENTICATE clause succeeding
2213			{
2214				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2215					Capabilities::default()
2216						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2217				);
2218				let sess = Session::owner().with_ns("test").with_db("test");
2219				let res = ds
2220					.execute(
2221						&format!(
2222							r#"
2223					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2224						AUTHENTICATE {{
2225							RETURN NONE
2226						}}
2227						DURATION FOR SESSION 2h
2228					;
2229					DEFINE USER tobie ON {} ROLES EDITOR;
2230					ACCESS api ON {} GRANT FOR USER tobie;
2231					"#,
2232							level.level, level.level, level.level
2233						),
2234						&sess,
2235						None,
2236					)
2237					.await
2238					.unwrap();
2239
2240				// Get the bearer key from grant
2241				let result = if let Ok(res) = &res.last().unwrap().result {
2242					res.clone()
2243				} else {
2244					panic!("Unable to retrieve bearer key grant");
2245				};
2246				let grant = result
2247					.coerce_to_object()
2248					.unwrap()
2249					.get("grant")
2250					.unwrap()
2251					.clone()
2252					.coerce_to_object()
2253					.unwrap();
2254				let key = grant.get("key").unwrap().clone().as_string();
2255
2256				// Sign in with the bearer key
2257				let mut sess = Session {
2258					ns: level.ns.map(String::from),
2259					db: level.db.map(String::from),
2260					..Default::default()
2261				};
2262				let mut vars: HashMap<&str, Value> = HashMap::new();
2263				vars.insert("key", key.into());
2264				let res = match level.level {
2265					"DB" => {
2266						db_access(
2267							&ds,
2268							&mut sess,
2269							level.ns.unwrap().to_string(),
2270							level.db.unwrap().to_string(),
2271							"api".to_string(),
2272							vars.into(),
2273						)
2274						.await
2275					}
2276					"NS" => {
2277						ns_access(
2278							&ds,
2279							&mut sess,
2280							level.ns.unwrap().to_string(),
2281							"api".to_string(),
2282							vars.into(),
2283						)
2284						.await
2285					}
2286					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
2287					_ => panic!("Unsupported level"),
2288				};
2289
2290				assert!(res.is_ok(), "Failed to sign in with bearer key: {:?}", res);
2291				assert_eq!(sess.ns, level.ns.map(|s| s.to_string()));
2292				assert_eq!(sess.db, level.db.map(|s| s.to_string()));
2293
2294				// Check auth level
2295				match level.level {
2296					"ROOT" => assert!(sess.au.is_root()),
2297					"NS" => assert!(sess.au.is_ns()),
2298					"DB" => assert!(sess.au.is_db()),
2299					_ => panic!("Unsupported level"),
2300				}
2301				assert_eq!(sess.au.level().ns(), level.ns);
2302				assert_eq!(sess.au.level().db(), level.db);
2303
2304				// Check roles
2305				assert!(
2306					!sess.au.has_role(Role::Viewer),
2307					"Auth user expected to not have Viewer role"
2308				);
2309				assert!(
2310					// User is defined with this role only
2311					sess.au.has_role(Role::Editor),
2312					"Auth user expected to have Editor role"
2313				);
2314				assert!(
2315					!sess.au.has_role(Role::Owner),
2316					"Auth user expected to not have Owner role"
2317				);
2318
2319				// Check expiration
2320				let exp = sess.exp.unwrap();
2321				let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
2322				let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
2323				assert!(
2324					exp > min_exp && exp < max_exp,
2325					"Session expiration is expected to match the defined duration",
2326				);
2327			}
2328
2329			// Test with correct bearer key and AUTHENTICATE clause failing
2330			{
2331				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2332					Capabilities::default()
2333						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2334				);
2335				let sess = Session::owner().with_ns("test").with_db("test");
2336				let res = ds
2337					.execute(
2338						&format!(
2339							r#"
2340					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2341						AUTHENTICATE {{
2342							THROW "Test authentication error";
2343						}}
2344						DURATION FOR SESSION 2h
2345					;
2346					DEFINE USER tobie ON {} ROLES EDITOR;
2347					ACCESS api ON {} GRANT FOR USER tobie;
2348					"#,
2349							level.level, level.level, level.level,
2350						),
2351						&sess,
2352						None,
2353					)
2354					.await
2355					.unwrap();
2356
2357				// Get the bearer key from grant
2358				let result = if let Ok(res) = &res.last().unwrap().result {
2359					res.clone()
2360				} else {
2361					panic!("Unable to retrieve bearer key grant");
2362				};
2363				let grant = result
2364					.coerce_to_object()
2365					.unwrap()
2366					.get("grant")
2367					.unwrap()
2368					.clone()
2369					.coerce_to_object()
2370					.unwrap();
2371				let key = grant.get("key").unwrap().clone().as_string();
2372
2373				// Sign in with the bearer key
2374				let mut sess = Session {
2375					ns: level.ns.map(String::from),
2376					db: level.db.map(String::from),
2377					..Default::default()
2378				};
2379				let mut vars: HashMap<&str, Value> = HashMap::new();
2380				vars.insert("key", key.into());
2381				let res = match level.level {
2382					"DB" => {
2383						db_access(
2384							&ds,
2385							&mut sess,
2386							level.ns.unwrap().to_string(),
2387							level.db.unwrap().to_string(),
2388							"api".to_string(),
2389							vars.into(),
2390						)
2391						.await
2392					}
2393					"NS" => {
2394						ns_access(
2395							&ds,
2396							&mut sess,
2397							level.ns.unwrap().to_string(),
2398							"api".to_string(),
2399							vars.into(),
2400						)
2401						.await
2402					}
2403					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
2404					_ => panic!("Unsupported level"),
2405				};
2406
2407				match res {
2408					Err(Error::Thrown(e)) => {
2409						assert_eq!(e, "Test authentication error")
2410					}
2411					res => panic!(
2412						"Expected a thrown authentication error, but instead received: {:?}",
2413						res
2414					),
2415				}
2416			}
2417
2418			// Test with expired grant
2419			{
2420				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2421					Capabilities::default()
2422						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2423				);
2424				let sess = Session::owner().with_ns("test").with_db("test");
2425				let res = ds
2426					.execute(
2427						&format!(
2428							r#"
2429					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2430						DURATION FOR GRANT 1s FOR SESSION 2h
2431					;
2432					DEFINE USER tobie ON {} ROLES EDITOR;
2433					ACCESS api ON {} GRANT FOR USER tobie;
2434					"#,
2435							level.level, level.level, level.level
2436						),
2437						&sess,
2438						None,
2439					)
2440					.await
2441					.unwrap();
2442
2443				// Get the bearer key from grant
2444				let result = if let Ok(res) = &res.last().unwrap().result {
2445					res.clone()
2446				} else {
2447					panic!("Unable to retrieve bearer key grant");
2448				};
2449				let grant = result
2450					.coerce_to_object()
2451					.unwrap()
2452					.get("grant")
2453					.unwrap()
2454					.clone()
2455					.coerce_to_object()
2456					.unwrap();
2457				let key = grant.get("key").unwrap().clone().as_string();
2458
2459				// Wait for the grant to expire
2460				std::thread::sleep(Duration::seconds(2).to_std().unwrap());
2461
2462				// Sign in with the bearer key
2463				let mut sess = Session {
2464					ns: level.ns.map(String::from),
2465					db: level.db.map(String::from),
2466					..Default::default()
2467				};
2468				let mut vars: HashMap<&str, Value> = HashMap::new();
2469				vars.insert("key", key.into());
2470				let res = match level.level {
2471					"DB" => {
2472						db_access(
2473							&ds,
2474							&mut sess,
2475							level.ns.unwrap().to_string(),
2476							level.db.unwrap().to_string(),
2477							"api".to_string(),
2478							vars.into(),
2479						)
2480						.await
2481					}
2482					"NS" => {
2483						ns_access(
2484							&ds,
2485							&mut sess,
2486							level.ns.unwrap().to_string(),
2487							"api".to_string(),
2488							vars.into(),
2489						)
2490						.await
2491					}
2492					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
2493					_ => panic!("Unsupported level"),
2494				};
2495
2496				match res {
2497					Err(Error::InvalidAuth) => {} // ok
2498					res => panic!(
2499						"Expected a generic authentication error, but instead received: {:?}",
2500						res
2501					),
2502				}
2503			}
2504
2505			// Test with revoked grant
2506			{
2507				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2508					Capabilities::default()
2509						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2510				);
2511				let sess = Session::owner().with_ns("test").with_db("test");
2512				let res = ds
2513					.execute(
2514						&format!(
2515							r#"
2516					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2517						DURATION FOR GRANT 1s FOR SESSION 2h
2518					;
2519					DEFINE USER tobie ON {} ROLES EDITOR;
2520					ACCESS api ON {} GRANT FOR USER tobie;
2521					"#,
2522							level.level, level.level, level.level
2523						),
2524						&sess,
2525						None,
2526					)
2527					.await
2528					.unwrap();
2529
2530				// Get the bearer key from grant
2531				let result = if let Ok(res) = &res.last().unwrap().result {
2532					res.clone()
2533				} else {
2534					panic!("Unable to retrieve bearer key grant");
2535				};
2536				let grant = result
2537					.coerce_to_object()
2538					.unwrap()
2539					.get("grant")
2540					.unwrap()
2541					.clone()
2542					.coerce_to_object()
2543					.unwrap();
2544				let key = grant.get("key").unwrap().clone().as_string();
2545
2546				// Get grant identifier from key
2547				let kid = key.split("-").collect::<Vec<&str>>()[2];
2548
2549				// Revoke grant
2550				ds.execute(
2551					&format!("ACCESS api ON {} REVOKE GRANT {kid}", level.level),
2552					&sess,
2553					None,
2554				)
2555				.await
2556				.unwrap();
2557
2558				// Sign in with the bearer key
2559				let mut sess = Session {
2560					ns: level.ns.map(String::from),
2561					db: level.db.map(String::from),
2562					..Default::default()
2563				};
2564				let mut vars: HashMap<&str, Value> = HashMap::new();
2565				vars.insert("key", key.into());
2566				let res = match level.level {
2567					"DB" => {
2568						db_access(
2569							&ds,
2570							&mut sess,
2571							level.ns.unwrap().to_string(),
2572							level.db.unwrap().to_string(),
2573							"api".to_string(),
2574							vars.into(),
2575						)
2576						.await
2577					}
2578					"NS" => {
2579						ns_access(
2580							&ds,
2581							&mut sess,
2582							level.ns.unwrap().to_string(),
2583							"api".to_string(),
2584							vars.into(),
2585						)
2586						.await
2587					}
2588					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
2589					_ => panic!("Unsupported level"),
2590				};
2591
2592				match res {
2593					Err(Error::InvalidAuth) => {} // ok
2594					res => panic!(
2595						"Expected a generic authentication error, but instead received: {:?}",
2596						res
2597					),
2598				}
2599			}
2600
2601			// Test with removed access method
2602			{
2603				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2604					Capabilities::default()
2605						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2606				);
2607				let sess = Session::owner().with_ns("test").with_db("test");
2608				let res = ds
2609					.execute(
2610						&format!(
2611							r#"
2612					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2613						DURATION FOR GRANT 1s FOR SESSION 2h
2614					;
2615					DEFINE USER tobie ON {} ROLES EDITOR;
2616					ACCESS api ON {} GRANT FOR USER tobie;
2617					"#,
2618							level.level, level.level, level.level
2619						),
2620						&sess,
2621						None,
2622					)
2623					.await
2624					.unwrap();
2625
2626				// Get the bearer key from grant
2627				let result = if let Ok(res) = &res.last().unwrap().result {
2628					res.clone()
2629				} else {
2630					panic!("Unable to retrieve bearer key grant");
2631				};
2632				let grant = result
2633					.coerce_to_object()
2634					.unwrap()
2635					.get("grant")
2636					.unwrap()
2637					.clone()
2638					.coerce_to_object()
2639					.unwrap();
2640				let key = grant.get("key").unwrap().clone().as_string();
2641
2642				// Remove bearer access method
2643				ds.execute(format!("REMOVE ACCESS api ON {}", level.level).as_str(), &sess, None)
2644					.await
2645					.unwrap();
2646
2647				// Sign in with the bearer key
2648				let mut sess = Session {
2649					ns: level.ns.map(String::from),
2650					db: level.db.map(String::from),
2651					..Default::default()
2652				};
2653				let mut vars: HashMap<&str, Value> = HashMap::new();
2654				vars.insert("key", key.into());
2655				let res = match level.level {
2656					"DB" => {
2657						db_access(
2658							&ds,
2659							&mut sess,
2660							level.ns.unwrap().to_string(),
2661							level.db.unwrap().to_string(),
2662							"api".to_string(),
2663							vars.into(),
2664						)
2665						.await
2666					}
2667					"NS" => {
2668						ns_access(
2669							&ds,
2670							&mut sess,
2671							level.ns.unwrap().to_string(),
2672							"api".to_string(),
2673							vars.into(),
2674						)
2675						.await
2676					}
2677					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
2678					_ => panic!("Unsupported level"),
2679				};
2680
2681				match res {
2682					Err(Error::AccessNotFound) => {} // ok
2683					res => panic!(
2684						"Expected an access method not found error, but instead received: {:?}",
2685						res
2686					),
2687				}
2688			}
2689
2690			// Test with missing key
2691			{
2692				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2693					Capabilities::default()
2694						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2695				);
2696				let sess = Session::owner().with_ns("test").with_db("test");
2697				let res = ds
2698					.execute(
2699						&format!(
2700							r#"
2701					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2702						DURATION FOR SESSION 2h
2703					;
2704					DEFINE USER tobie ON {} ROLES EDITOR;
2705					ACCESS api ON {} GRANT FOR USER tobie;
2706					"#,
2707							level.level, level.level, level.level
2708						),
2709						&sess,
2710						None,
2711					)
2712					.await
2713					.unwrap();
2714
2715				// Get the bearer key from grant
2716				let result = if let Ok(res) = &res.last().unwrap().result {
2717					res.clone()
2718				} else {
2719					panic!("Unable to retrieve bearer key grant");
2720				};
2721				let grant = result
2722					.coerce_to_object()
2723					.unwrap()
2724					.get("grant")
2725					.unwrap()
2726					.clone()
2727					.coerce_to_object()
2728					.unwrap();
2729				let _key = grant.get("key").unwrap().clone().as_string();
2730
2731				// Sign in with the bearer key
2732				let mut sess = Session {
2733					ns: level.ns.map(String::from),
2734					db: level.db.map(String::from),
2735					..Default::default()
2736				};
2737
2738				// The key parameter is not inserted:
2739				let vars: HashMap<&str, Value> = HashMap::new();
2740				// vars.insert("key", key.into());
2741
2742				let res = match level.level {
2743					"DB" => {
2744						db_access(
2745							&ds,
2746							&mut sess,
2747							level.ns.unwrap().to_string(),
2748							level.db.unwrap().to_string(),
2749							"api".to_string(),
2750							vars.into(),
2751						)
2752						.await
2753					}
2754					"NS" => {
2755						ns_access(
2756							&ds,
2757							&mut sess,
2758							level.ns.unwrap().to_string(),
2759							"api".to_string(),
2760							vars.into(),
2761						)
2762						.await
2763					}
2764					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
2765					_ => panic!("Unsupported level"),
2766				};
2767
2768				match res {
2769					Err(Error::AccessBearerMissingKey) => {} // ok
2770					res => panic!(
2771						"Expected a missing key authentication error, but instead received: {:?}",
2772						res
2773					),
2774				}
2775			}
2776
2777			// Test with incorrect bearer key prefix part
2778			{
2779				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2780					Capabilities::default()
2781						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2782				);
2783				let sess = Session::owner().with_ns("test").with_db("test");
2784				let res = ds
2785					.execute(
2786						&format!(
2787							r#"
2788					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2789						DURATION FOR SESSION 2h
2790					;
2791					DEFINE USER tobie ON {} ROLES EDITOR;
2792					ACCESS api ON {} GRANT FOR USER tobie;
2793					"#,
2794							level.level, level.level, level.level
2795						),
2796						&sess,
2797						None,
2798					)
2799					.await
2800					.unwrap();
2801
2802				// Get the bearer key from grant
2803				let result = if let Ok(res) = &res.last().unwrap().result {
2804					res.clone()
2805				} else {
2806					panic!("Unable to retrieve bearer key grant");
2807				};
2808				let grant = result
2809					.coerce_to_object()
2810					.unwrap()
2811					.get("grant")
2812					.unwrap()
2813					.clone()
2814					.coerce_to_object()
2815					.unwrap();
2816				let valid_key = grant.get("key").unwrap().clone().as_string();
2817
2818				// Replace a character from the key prefix
2819				let mut invalid_key: Vec<char> = valid_key.chars().collect();
2820				invalid_key["surreal-".len() + 2] = '_';
2821				let key: String = invalid_key.into_iter().collect();
2822
2823				// Sign in with the bearer key
2824				let mut sess = Session {
2825					ns: level.ns.map(String::from),
2826					db: level.db.map(String::from),
2827					..Default::default()
2828				};
2829				let mut vars: HashMap<&str, Value> = HashMap::new();
2830				vars.insert("key", key.into());
2831				let res = match level.level {
2832					"DB" => {
2833						db_access(
2834							&ds,
2835							&mut sess,
2836							level.ns.unwrap().to_string(),
2837							level.db.unwrap().to_string(),
2838							"api".to_string(),
2839							vars.into(),
2840						)
2841						.await
2842					}
2843					"NS" => {
2844						ns_access(
2845							&ds,
2846							&mut sess,
2847							level.ns.unwrap().to_string(),
2848							"api".to_string(),
2849							vars.into(),
2850						)
2851						.await
2852					}
2853					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
2854					_ => panic!("Unsupported level"),
2855				};
2856
2857				match res {
2858					Err(Error::AccessGrantBearerInvalid) => {} // ok
2859					res => panic!(
2860						"Expected an invalid key authentication error, but instead received: {:?}",
2861						res
2862					),
2863				}
2864			}
2865
2866			// Test with incorrect bearer key length
2867			{
2868				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2869					Capabilities::default()
2870						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2871				);
2872				let sess = Session::owner().with_ns("test").with_db("test");
2873				let res = ds
2874					.execute(
2875						&format!(
2876							r#"
2877					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2878						DURATION FOR SESSION 2h
2879					;
2880					DEFINE USER tobie ON {} ROLES EDITOR;
2881					ACCESS api ON {} GRANT FOR USER tobie;
2882					"#,
2883							level.level, level.level, level.level
2884						),
2885						&sess,
2886						None,
2887					)
2888					.await
2889					.unwrap();
2890
2891				// Get the bearer key from grant
2892				let result = if let Ok(res) = &res.last().unwrap().result {
2893					res.clone()
2894				} else {
2895					panic!("Unable to retrieve bearer key grant");
2896				};
2897				let grant = result
2898					.coerce_to_object()
2899					.unwrap()
2900					.get("grant")
2901					.unwrap()
2902					.clone()
2903					.coerce_to_object()
2904					.unwrap();
2905				let valid_key = grant.get("key").unwrap().clone().as_string();
2906
2907				// Remove a character from the bearer key
2908				let mut invalid_key: Vec<char> = valid_key.chars().collect();
2909				invalid_key.truncate(invalid_key.len() - 1);
2910				let key: String = invalid_key.into_iter().collect();
2911
2912				// Sign in with the bearer key
2913				let mut sess = Session {
2914					ns: level.ns.map(String::from),
2915					db: level.db.map(String::from),
2916					..Default::default()
2917				};
2918				let mut vars: HashMap<&str, Value> = HashMap::new();
2919				vars.insert("key", key.into());
2920				let res = match level.level {
2921					"DB" => {
2922						db_access(
2923							&ds,
2924							&mut sess,
2925							level.ns.unwrap().to_string(),
2926							level.db.unwrap().to_string(),
2927							"api".to_string(),
2928							vars.into(),
2929						)
2930						.await
2931					}
2932					"NS" => {
2933						ns_access(
2934							&ds,
2935							&mut sess,
2936							level.ns.unwrap().to_string(),
2937							"api".to_string(),
2938							vars.into(),
2939						)
2940						.await
2941					}
2942					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
2943					_ => panic!("Unsupported level"),
2944				};
2945
2946				match res {
2947					Err(Error::AccessGrantBearerInvalid) => {} // ok
2948					res => panic!(
2949						"Expected an invalid key authentication error, but instead received: {:?}",
2950						res
2951					),
2952				}
2953			}
2954
2955			// Test with incorrect bearer key identifier part
2956			{
2957				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
2958					Capabilities::default()
2959						.with_experimental(ExperimentalTarget::BearerAccess.into()),
2960				);
2961				let sess = Session::owner().with_ns("test").with_db("test");
2962				let res = ds
2963					.execute(
2964						&format!(
2965							r#"
2966					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
2967						DURATION FOR SESSION 2h
2968					;
2969					DEFINE USER tobie ON {} ROLES EDITOR;
2970					ACCESS api ON {} GRANT FOR USER tobie;
2971					"#,
2972							level.level, level.level, level.level
2973						),
2974						&sess,
2975						None,
2976					)
2977					.await
2978					.unwrap();
2979
2980				// Get the bearer key from grant
2981				let result = if let Ok(res) = &res.last().unwrap().result {
2982					res.clone()
2983				} else {
2984					panic!("Unable to retrieve bearer key grant");
2985				};
2986				let grant = result
2987					.coerce_to_object()
2988					.unwrap()
2989					.get("grant")
2990					.unwrap()
2991					.clone()
2992					.coerce_to_object()
2993					.unwrap();
2994				let valid_key = grant.get("key").unwrap().clone().as_string();
2995
2996				// Replace a character from the key identifier
2997				let mut invalid_key: Vec<char> = valid_key.chars().collect();
2998				invalid_key[access_type::BearerAccessType::Bearer.prefix().len() + 2] = '_';
2999				let key: String = invalid_key.into_iter().collect();
3000
3001				// Sign in with the bearer key
3002				let mut sess = Session {
3003					ns: level.ns.map(String::from),
3004					db: level.db.map(String::from),
3005					..Default::default()
3006				};
3007				let mut vars: HashMap<&str, Value> = HashMap::new();
3008				vars.insert("key", key.into());
3009				let res = match level.level {
3010					"DB" => {
3011						db_access(
3012							&ds,
3013							&mut sess,
3014							level.ns.unwrap().to_string(),
3015							level.db.unwrap().to_string(),
3016							"api".to_string(),
3017							vars.into(),
3018						)
3019						.await
3020					}
3021					"NS" => {
3022						ns_access(
3023							&ds,
3024							&mut sess,
3025							level.ns.unwrap().to_string(),
3026							"api".to_string(),
3027							vars.into(),
3028						)
3029						.await
3030					}
3031					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
3032					_ => panic!("Unsupported level"),
3033				};
3034
3035				match res {
3036					Err(Error::InvalidAuth) => {} // ok
3037					res => panic!(
3038						"Expected a generic authentication error, but instead received: {:?}",
3039						res
3040					),
3041				}
3042			}
3043
3044			// Test with incorrect bearer key value
3045			{
3046				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3047					Capabilities::default()
3048						.with_experimental(ExperimentalTarget::BearerAccess.into()),
3049				);
3050				let sess = Session::owner().with_ns("test").with_db("test");
3051				let res = ds
3052					.execute(
3053						&format!(
3054							r#"
3055					DEFINE ACCESS api ON {} TYPE BEARER FOR USER
3056						DURATION FOR SESSION 2h
3057					;
3058					DEFINE USER tobie ON {} ROLES EDITOR;
3059					ACCESS api ON {} GRANT FOR USER tobie;
3060					"#,
3061							level.level, level.level, level.level
3062						),
3063						&sess,
3064						None,
3065					)
3066					.await
3067					.unwrap();
3068
3069				// Get the bearer key from grant
3070				let result = if let Ok(res) = &res.last().unwrap().result {
3071					res.clone()
3072				} else {
3073					panic!("Unable to retrieve bearer key grant");
3074				};
3075				let grant = result
3076					.coerce_to_object()
3077					.unwrap()
3078					.get("grant")
3079					.unwrap()
3080					.clone()
3081					.coerce_to_object()
3082					.unwrap();
3083				let valid_key = grant.get("key").unwrap().clone().as_string();
3084
3085				// Replace a character from the key value
3086				let mut invalid_key: Vec<char> = valid_key.chars().collect();
3087				invalid_key[valid_key.len() - 2] = '_';
3088				let key: String = invalid_key.into_iter().collect();
3089
3090				// Sign in with the bearer key
3091				let mut sess = Session {
3092					ns: level.ns.map(String::from),
3093					db: level.db.map(String::from),
3094					..Default::default()
3095				};
3096				let mut vars: HashMap<&str, Value> = HashMap::new();
3097				vars.insert("key", key.into());
3098				let res = match level.level {
3099					"DB" => {
3100						db_access(
3101							&ds,
3102							&mut sess,
3103							level.ns.unwrap().to_string(),
3104							level.db.unwrap().to_string(),
3105							"api".to_string(),
3106							vars.into(),
3107						)
3108						.await
3109					}
3110					"NS" => {
3111						ns_access(
3112							&ds,
3113							&mut sess,
3114							level.ns.unwrap().to_string(),
3115							"api".to_string(),
3116							vars.into(),
3117						)
3118						.await
3119					}
3120					"ROOT" => root_access(&ds, &mut sess, "api".to_string(), vars.into()).await,
3121					_ => panic!("Unsupported level"),
3122				};
3123
3124				match res {
3125					Err(Error::InvalidAuth) => {} // ok
3126					res => panic!(
3127						"Expected a generic authentication error, but instead received: {:?}",
3128						res
3129					),
3130				}
3131			}
3132
3133			// Test that only the key hash is stored
3134			{
3135				let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3136					Capabilities::default()
3137						.with_experimental(ExperimentalTarget::BearerAccess.into()),
3138				);
3139				let sess = Session::owner().with_ns("test").with_db("test");
3140				let res = ds
3141					.execute(
3142						&format!(
3143							r#"
3144						DEFINE ACCESS api ON {} TYPE BEARER FOR USER
3145							DURATION FOR SESSION 2h
3146						;
3147						DEFINE USER tobie ON {} ROLES EDITOR;
3148						ACCESS api ON {} GRANT FOR USER tobie;
3149						"#,
3150							level.level, level.level, level.level
3151						),
3152						&sess,
3153						None,
3154					)
3155					.await
3156					.unwrap();
3157
3158				// Get the bearer key from grant
3159				let result = if let Ok(res) = &res.last().unwrap().result {
3160					res.clone()
3161				} else {
3162					panic!("Unable to retrieve bearer key grant");
3163				};
3164				let grant = result
3165					.coerce_to_object()
3166					.unwrap()
3167					.get("grant")
3168					.unwrap()
3169					.clone()
3170					.coerce_to_object()
3171					.unwrap();
3172				let id = grant.get("id").unwrap().clone().as_string();
3173				let key = grant.get("key").unwrap().clone().as_string();
3174
3175				// Test that returned key is in plain text
3176				assert!(
3177					plain_text_regex.is_match(&key),
3178					"Output '{}' doesn't match regex '{}'",
3179					key,
3180					plain_text_regex
3181				);
3182
3183				// Get the stored bearer grant
3184				let tx = ds.transaction(Read, Optimistic).await.unwrap().enclose();
3185				let grant = match level.level {
3186					"DB" => tx
3187						.get_db_access_grant(level.ns.unwrap(), level.db.unwrap(), "api", &id)
3188						.await
3189						.unwrap(),
3190					"NS" => tx.get_ns_access_grant(level.ns.unwrap(), "api", &id).await.unwrap(),
3191					"ROOT" => tx.get_root_access_grant("api", &id).await.unwrap(),
3192					_ => panic!("Unsupported level"),
3193				};
3194				let key = match &grant.grant {
3195					access::Grant::Bearer(grant) => grant.key.clone(),
3196					_ => panic!("Incorrect grant type returned, expected a bearer grant"),
3197				};
3198				tx.cancel().await.unwrap();
3199
3200				// Test that the returned key is a SHA-256 hash
3201				assert!(
3202					sha_256_regex.is_match(&key),
3203					"Output '{}' doesn't match regex '{}'",
3204					key,
3205					sha_256_regex
3206				);
3207			}
3208		}
3209	}
3210
3211	#[tokio::test]
3212	async fn test_signin_bearer_for_record() {
3213		// Test with correct bearer key and existing record
3214		{
3215			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3216				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3217			);
3218			let sess = Session::owner().with_ns("test").with_db("test");
3219			let res = ds
3220				.execute(
3221					r#"
3222				DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3223					DURATION FOR SESSION 2h
3224				;
3225				CREATE user:test;
3226				ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3227				"#,
3228					&sess,
3229					None,
3230				)
3231				.await
3232				.unwrap();
3233
3234			// Get the bearer key from grant
3235			let result = if let Ok(res) = &res.last().unwrap().result {
3236				res.clone()
3237			} else {
3238				panic!("Unable to retrieve bearer key grant");
3239			};
3240			let grant = result
3241				.coerce_to_object()
3242				.unwrap()
3243				.get("grant")
3244				.unwrap()
3245				.clone()
3246				.coerce_to_object()
3247				.unwrap();
3248			let key = grant.get("key").unwrap().clone().as_string();
3249
3250			// Sign in with the bearer key
3251			let mut sess = Session {
3252				ns: Some("test".to_string()),
3253				db: Some("test".to_string()),
3254				..Default::default()
3255			};
3256			let mut vars: HashMap<&str, Value> = HashMap::new();
3257			vars.insert("key", key.into());
3258			let res = db_access(
3259				&ds,
3260				&mut sess,
3261				"test".to_string(),
3262				"test".to_string(),
3263				"api".to_string(),
3264				vars.into(),
3265			)
3266			.await;
3267			assert!(res.is_ok(), "Failed to sign in with bearer key: {:?}", res);
3268			assert_eq!(sess.ns, Some("test".to_string()));
3269			assert_eq!(sess.db, Some("test".to_string()));
3270			assert_eq!(sess.au.id(), "user:test");
3271			assert!(sess.au.is_record());
3272			assert_eq!(sess.au.level().ns(), Some("test"));
3273			assert_eq!(sess.au.level().db(), Some("test"));
3274			assert_eq!(sess.au.level().id(), Some("user:test"));
3275			// Record users should not have roles
3276			assert!(!sess.au.has_role(Role::Viewer), "Auth user expected to not have Viewer role");
3277			assert!(!sess.au.has_role(Role::Editor), "Auth user expected to not have Editor role");
3278			assert!(!sess.au.has_role(Role::Owner), "Auth user expected to not have Owner role");
3279			// Expiration should match the defined duration
3280			let exp = sess.exp.unwrap();
3281			// Expiration should match the current time plus session duration with some margin
3282			let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
3283			let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
3284			assert!(
3285				exp > min_exp && exp < max_exp,
3286				"Session expiration is expected to follow the defined duration"
3287			);
3288		}
3289		// Test with correct bearer key and non-existing record
3290		{
3291			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3292				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3293			);
3294			let sess = Session::owner().with_ns("test").with_db("test");
3295			let res = ds
3296				.execute(
3297					r#"
3298				DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3299					DURATION FOR SESSION 2h
3300				;
3301				ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3302				"#,
3303					&sess,
3304					None,
3305				)
3306				.await
3307				.unwrap();
3308
3309			// Get the bearer key from grant
3310			let result = if let Ok(res) = &res.last().unwrap().result {
3311				res.clone()
3312			} else {
3313				panic!("Unable to retrieve bearer key grant");
3314			};
3315			let grant = result
3316				.coerce_to_object()
3317				.unwrap()
3318				.get("grant")
3319				.unwrap()
3320				.clone()
3321				.coerce_to_object()
3322				.unwrap();
3323			let key = grant.get("key").unwrap().clone().as_string();
3324
3325			// Sign in with the bearer key
3326			let mut sess = Session {
3327				ns: Some("test".to_string()),
3328				db: Some("test".to_string()),
3329				..Default::default()
3330			};
3331			let mut vars: HashMap<&str, Value> = HashMap::new();
3332			vars.insert("key", key.into());
3333			let res = db_access(
3334				&ds,
3335				&mut sess,
3336				"test".to_string(),
3337				"test".to_string(),
3338				"api".to_string(),
3339				vars.into(),
3340			)
3341			.await;
3342
3343			assert!(res.is_ok(), "Failed to sign in with bearer key: {:?}", res);
3344			assert_eq!(sess.ns, Some("test".to_string()));
3345			assert_eq!(sess.db, Some("test".to_string()));
3346			assert_eq!(sess.au.id(), "user:test");
3347			assert!(sess.au.is_record());
3348			assert_eq!(sess.au.level().ns(), Some("test"));
3349			assert_eq!(sess.au.level().db(), Some("test"));
3350			assert_eq!(sess.au.level().id(), Some("user:test"));
3351			// Record users should not have roles
3352			assert!(!sess.au.has_role(Role::Viewer), "Auth user expected to not have Viewer role");
3353			assert!(!sess.au.has_role(Role::Editor), "Auth user expected to not have Editor role");
3354			assert!(!sess.au.has_role(Role::Owner), "Auth user expected to not have Owner role");
3355			// Expiration should match the defined duration
3356			let exp = sess.exp.unwrap();
3357			// Expiration should match the current time plus session duration with some margin
3358			let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
3359			let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
3360			assert!(
3361				exp > min_exp && exp < max_exp,
3362				"Session expiration is expected to follow the defined duration"
3363			);
3364		}
3365		// Test with correct bearer key and AUTHENTICATE clause succeeding
3366		{
3367			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3368				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3369			);
3370			let sess = Session::owner().with_ns("test").with_db("test");
3371			let res = ds
3372				.execute(
3373					r#"
3374					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3375						AUTHENTICATE {{
3376							RETURN NONE
3377						}}
3378						DURATION FOR SESSION 2h
3379					;
3380					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3381					"#,
3382					&sess,
3383					None,
3384				)
3385				.await
3386				.unwrap();
3387
3388			// Get the bearer key from grant
3389			let result = if let Ok(res) = &res.last().unwrap().result {
3390				res.clone()
3391			} else {
3392				panic!("Unable to retrieve bearer key grant");
3393			};
3394			let grant = result
3395				.coerce_to_object()
3396				.unwrap()
3397				.get("grant")
3398				.unwrap()
3399				.clone()
3400				.coerce_to_object()
3401				.unwrap();
3402			let key = grant.get("key").unwrap().clone().as_string();
3403
3404			// Sign in with the bearer key
3405			let mut sess = Session {
3406				ns: Some("test".to_string()),
3407				db: Some("test".to_string()),
3408				..Default::default()
3409			};
3410			let mut vars: HashMap<&str, Value> = HashMap::new();
3411			vars.insert("key", key.into());
3412			let res = db_access(
3413				&ds,
3414				&mut sess,
3415				"test".to_string(),
3416				"test".to_string(),
3417				"api".to_string(),
3418				vars.into(),
3419			)
3420			.await;
3421
3422			assert!(res.is_ok(), "Failed to sign in with bearer key: {:?}", res);
3423			assert_eq!(sess.ns, Some("test".to_string()));
3424			assert_eq!(sess.db, Some("test".to_string()));
3425			assert_eq!(sess.au.id(), "user:test");
3426			assert!(sess.au.is_record());
3427			assert_eq!(sess.au.level().ns(), Some("test"));
3428			assert_eq!(sess.au.level().db(), Some("test"));
3429			assert_eq!(sess.au.level().id(), Some("user:test"));
3430			// Record users should not have roles
3431			assert!(!sess.au.has_role(Role::Viewer), "Auth user expected to not have Viewer role");
3432			assert!(!sess.au.has_role(Role::Editor), "Auth user expected to not have Editor role");
3433			assert!(!sess.au.has_role(Role::Owner), "Auth user expected to not have Owner role");
3434			// Expiration should match the defined duration
3435			let exp = sess.exp.unwrap();
3436			// Expiration should match the current time plus session duration with some margin
3437			let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
3438			let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
3439			assert!(
3440				exp > min_exp && exp < max_exp,
3441				"Session expiration is expected to follow the defined duration"
3442			);
3443		}
3444
3445		// Test with correct bearer key and AUTHENTICATE clause failing
3446		{
3447			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3448				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3449			);
3450			let sess = Session::owner().with_ns("test").with_db("test");
3451			let res = ds
3452				.execute(
3453					r#"
3454					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3455						AUTHENTICATE {{
3456							THROW "Test authentication error";
3457						}}
3458						DURATION FOR SESSION 2h
3459					;
3460					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3461					"#,
3462					&sess,
3463					None,
3464				)
3465				.await
3466				.unwrap();
3467
3468			// Get the bearer key from grant
3469			let result = if let Ok(res) = &res.last().unwrap().result {
3470				res.clone()
3471			} else {
3472				panic!("Unable to retrieve bearer key grant");
3473			};
3474			let grant = result
3475				.coerce_to_object()
3476				.unwrap()
3477				.get("grant")
3478				.unwrap()
3479				.clone()
3480				.coerce_to_object()
3481				.unwrap();
3482			let key = grant.get("key").unwrap().clone().as_string();
3483
3484			// Sign in with the bearer key
3485			let mut sess = Session {
3486				ns: Some("test".to_string()),
3487				db: Some("test".to_string()),
3488				..Default::default()
3489			};
3490			let mut vars: HashMap<&str, Value> = HashMap::new();
3491			vars.insert("key", key.into());
3492			let res = db_access(
3493				&ds,
3494				&mut sess,
3495				"test".to_string(),
3496				"test".to_string(),
3497				"api".to_string(),
3498				vars.into(),
3499			)
3500			.await;
3501
3502			match res {
3503				Err(Error::Thrown(e)) => {
3504					assert_eq!(e, "Test authentication error")
3505				}
3506				res => panic!(
3507					"Expected a thrown authentication error, but instead received: {:?}",
3508					res
3509				),
3510			}
3511		}
3512
3513		// Test with expired grant
3514		{
3515			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3516				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3517			);
3518			let sess = Session::owner().with_ns("test").with_db("test");
3519			let res = ds
3520				.execute(
3521					r#"
3522					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3523						DURATION FOR GRANT 1s FOR SESSION 2h
3524					;
3525					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3526					"#,
3527					&sess,
3528					None,
3529				)
3530				.await
3531				.unwrap();
3532
3533			// Get the bearer key from grant
3534			let result = if let Ok(res) = &res.last().unwrap().result {
3535				res.clone()
3536			} else {
3537				panic!("Unable to retrieve bearer key grant");
3538			};
3539			let grant = result
3540				.coerce_to_object()
3541				.unwrap()
3542				.get("grant")
3543				.unwrap()
3544				.clone()
3545				.coerce_to_object()
3546				.unwrap();
3547			let key = grant.get("key").unwrap().clone().as_string();
3548
3549			// Wait for the grant to expire
3550			std::thread::sleep(Duration::seconds(2).to_std().unwrap());
3551
3552			// Sign in with the bearer key
3553			let mut sess = Session {
3554				ns: Some("test".to_string()),
3555				db: Some("test".to_string()),
3556				..Default::default()
3557			};
3558			let mut vars: HashMap<&str, Value> = HashMap::new();
3559			vars.insert("key", key.into());
3560			let res = db_access(
3561				&ds,
3562				&mut sess,
3563				"test".to_string(),
3564				"test".to_string(),
3565				"api".to_string(),
3566				vars.into(),
3567			)
3568			.await;
3569
3570			match res {
3571				Err(Error::InvalidAuth) => {} // ok
3572				res => panic!(
3573					"Expected a generic authentication error, but instead received: {:?}",
3574					res
3575				),
3576			}
3577		}
3578
3579		// Test with revoked grant
3580		{
3581			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3582				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3583			);
3584			let sess = Session::owner().with_ns("test").with_db("test");
3585			let res = ds
3586				.execute(
3587					r#"
3588					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3589						DURATION FOR GRANT 1s FOR SESSION 2h
3590					;
3591					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3592					"#,
3593					&sess,
3594					None,
3595				)
3596				.await
3597				.unwrap();
3598
3599			// Get the bearer key from grant
3600			let result = if let Ok(res) = &res.last().unwrap().result {
3601				res.clone()
3602			} else {
3603				panic!("Unable to retrieve bearer key grant");
3604			};
3605			let grant = result
3606				.coerce_to_object()
3607				.unwrap()
3608				.get("grant")
3609				.unwrap()
3610				.clone()
3611				.coerce_to_object()
3612				.unwrap();
3613			let key = grant.get("key").unwrap().clone().as_string();
3614
3615			// Get grant identifier from key
3616			let kid = key.split("-").collect::<Vec<&str>>()[2];
3617
3618			// Revoke grant
3619			ds.execute(&format!("ACCESS api ON DATABASE REVOKE GRANT {kid}"), &sess, None)
3620				.await
3621				.unwrap();
3622
3623			// Sign in with the bearer key
3624			let mut sess = Session {
3625				ns: Some("test".to_string()),
3626				db: Some("test".to_string()),
3627				..Default::default()
3628			};
3629			let mut vars: HashMap<&str, Value> = HashMap::new();
3630			vars.insert("key", key.into());
3631			let res = db_access(
3632				&ds,
3633				&mut sess,
3634				"test".to_string(),
3635				"test".to_string(),
3636				"api".to_string(),
3637				vars.into(),
3638			)
3639			.await;
3640
3641			match res {
3642				Err(Error::InvalidAuth) => {} // ok
3643				res => panic!(
3644					"Expected a generic authentication error, but instead received: {:?}",
3645					res
3646				),
3647			}
3648		}
3649
3650		// Test with removed access method
3651		{
3652			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3653				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3654			);
3655			let sess = Session::owner().with_ns("test").with_db("test");
3656			let res = ds
3657				.execute(
3658					r#"
3659					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3660						DURATION FOR GRANT 1s FOR SESSION 2h
3661					;
3662					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3663					"#,
3664					&sess,
3665					None,
3666				)
3667				.await
3668				.unwrap();
3669
3670			// Get the bearer key from grant
3671			let result = if let Ok(res) = &res.last().unwrap().result {
3672				res.clone()
3673			} else {
3674				panic!("Unable to retrieve bearer key grant");
3675			};
3676			let grant = result
3677				.coerce_to_object()
3678				.unwrap()
3679				.get("grant")
3680				.unwrap()
3681				.clone()
3682				.coerce_to_object()
3683				.unwrap();
3684			let key = grant.get("key").unwrap().clone().as_string();
3685
3686			// Remove bearer access method
3687			ds.execute("REMOVE ACCESS api ON DATABASE", &sess, None).await.unwrap();
3688
3689			// Sign in with the bearer key
3690			let mut sess = Session {
3691				ns: Some("test".to_string()),
3692				db: Some("test".to_string()),
3693				..Default::default()
3694			};
3695			let mut vars: HashMap<&str, Value> = HashMap::new();
3696			vars.insert("key", key.into());
3697			let res = db_access(
3698				&ds,
3699				&mut sess,
3700				"test".to_string(),
3701				"test".to_string(),
3702				"api".to_string(),
3703				vars.into(),
3704			)
3705			.await;
3706
3707			match res {
3708				Err(Error::AccessNotFound) => {} // ok
3709				res => panic!(
3710					"Expected an access method not found error, but instead received: {:?}",
3711					res
3712				),
3713			}
3714		}
3715
3716		// Test with missing key
3717		{
3718			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3719				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3720			);
3721			let sess = Session::owner().with_ns("test").with_db("test");
3722			let res = ds
3723				.execute(
3724					r#"
3725					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3726						DURATION FOR SESSION 2h
3727					;
3728					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3729					"#,
3730					&sess,
3731					None,
3732				)
3733				.await
3734				.unwrap();
3735
3736			// Get the bearer key from grant
3737			let result = if let Ok(res) = &res.last().unwrap().result {
3738				res.clone()
3739			} else {
3740				panic!("Unable to retrieve bearer key grant");
3741			};
3742			let grant = result
3743				.coerce_to_object()
3744				.unwrap()
3745				.get("grant")
3746				.unwrap()
3747				.clone()
3748				.coerce_to_object()
3749				.unwrap();
3750			let _key = grant.get("key").unwrap().clone().as_string();
3751
3752			// Sign in with the bearer key
3753			let mut sess = Session {
3754				ns: Some("test".to_string()),
3755				db: Some("test".to_string()),
3756				..Default::default()
3757			};
3758			// The key parameter is not inserted:
3759			let vars: HashMap<&str, Value> = HashMap::new();
3760			// vars.insert("key", key.into());
3761			let res = db_access(
3762				&ds,
3763				&mut sess,
3764				"test".to_string(),
3765				"test".to_string(),
3766				"api".to_string(),
3767				vars.into(),
3768			)
3769			.await;
3770
3771			match res {
3772				Err(Error::AccessBearerMissingKey) => {} // ok
3773				res => panic!(
3774					"Expected a missing key authentication error, but instead received: {:?}",
3775					res
3776				),
3777			}
3778		}
3779
3780		// Test with incorrect bearer key prefix part
3781		{
3782			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3783				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3784			);
3785			let sess = Session::owner().with_ns("test").with_db("test");
3786			let res = ds
3787				.execute(
3788					r#"
3789					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3790						DURATION FOR SESSION 2h
3791					;
3792					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3793					"#,
3794					&sess,
3795					None,
3796				)
3797				.await
3798				.unwrap();
3799
3800			// Get the bearer key from grant
3801			let result = if let Ok(res) = &res.last().unwrap().result {
3802				res.clone()
3803			} else {
3804				panic!("Unable to retrieve bearer key grant");
3805			};
3806			let grant = result
3807				.coerce_to_object()
3808				.unwrap()
3809				.get("grant")
3810				.unwrap()
3811				.clone()
3812				.coerce_to_object()
3813				.unwrap();
3814			let valid_key = grant.get("key").unwrap().clone().as_string();
3815
3816			// Replace a character from the key prefix
3817			let mut invalid_key: Vec<char> = valid_key.chars().collect();
3818			invalid_key["surreal-".len() + 2] = '_';
3819			let key: String = invalid_key.into_iter().collect();
3820
3821			// Sign in with the bearer key
3822			let mut sess = Session {
3823				ns: Some("test".to_string()),
3824				db: Some("test".to_string()),
3825				..Default::default()
3826			};
3827			let mut vars: HashMap<&str, Value> = HashMap::new();
3828			vars.insert("key", key.into());
3829			let res = db_access(
3830				&ds,
3831				&mut sess,
3832				"test".to_string(),
3833				"test".to_string(),
3834				"api".to_string(),
3835				vars.into(),
3836			)
3837			.await;
3838
3839			match res {
3840				Err(Error::AccessGrantBearerInvalid) => {} // ok
3841				res => panic!(
3842					"Expected an invalid key authentication error, but instead received: {:?}",
3843					res
3844				),
3845			}
3846		}
3847
3848		// Test with incorrect bearer key length
3849		{
3850			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3851				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3852			);
3853			let sess = Session::owner().with_ns("test").with_db("test");
3854			let res = ds
3855				.execute(
3856					r#"
3857					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3858						DURATION FOR SESSION 2h
3859					;
3860					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3861					"#,
3862					&sess,
3863					None,
3864				)
3865				.await
3866				.unwrap();
3867
3868			// Get the bearer key from grant
3869			let result = if let Ok(res) = &res.last().unwrap().result {
3870				res.clone()
3871			} else {
3872				panic!("Unable to retrieve bearer key grant");
3873			};
3874			let grant = result
3875				.coerce_to_object()
3876				.unwrap()
3877				.get("grant")
3878				.unwrap()
3879				.clone()
3880				.coerce_to_object()
3881				.unwrap();
3882			let valid_key = grant.get("key").unwrap().clone().as_string();
3883
3884			// Remove a character from the bearer key
3885			let mut invalid_key: Vec<char> = valid_key.chars().collect();
3886			invalid_key.truncate(invalid_key.len() - 1);
3887			let key: String = invalid_key.into_iter().collect();
3888
3889			// Sign in with the bearer key
3890			let mut sess = Session {
3891				ns: Some("test".to_string()),
3892				db: Some("test".to_string()),
3893				..Default::default()
3894			};
3895			let mut vars: HashMap<&str, Value> = HashMap::new();
3896			vars.insert("key", key.into());
3897			let res = db_access(
3898				&ds,
3899				&mut sess,
3900				"test".to_string(),
3901				"test".to_string(),
3902				"api".to_string(),
3903				vars.into(),
3904			)
3905			.await;
3906
3907			match res {
3908				Err(Error::AccessGrantBearerInvalid) => {} // ok
3909				res => panic!(
3910					"Expected an invalid key authentication error, but instead received: {:?}",
3911					res
3912				),
3913			}
3914		}
3915
3916		// Test with incorrect bearer key identifier part
3917		{
3918			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3919				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3920			);
3921			let sess = Session::owner().with_ns("test").with_db("test");
3922			let res = ds
3923				.execute(
3924					r#"
3925					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3926						DURATION FOR SESSION 2h
3927					;
3928					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3929					"#,
3930					&sess,
3931					None,
3932				)
3933				.await
3934				.unwrap();
3935
3936			// Get the bearer key from grant
3937			let result = if let Ok(res) = &res.last().unwrap().result {
3938				res.clone()
3939			} else {
3940				panic!("Unable to retrieve bearer key grant");
3941			};
3942			let grant = result
3943				.coerce_to_object()
3944				.unwrap()
3945				.get("grant")
3946				.unwrap()
3947				.clone()
3948				.coerce_to_object()
3949				.unwrap();
3950			let valid_key = grant.get("key").unwrap().clone().as_string();
3951
3952			// Replace a character from the key identifier
3953			let mut invalid_key: Vec<char> = valid_key.chars().collect();
3954			invalid_key[access_type::BearerAccessType::Bearer.prefix().len() + 2] = '_';
3955			let key: String = invalid_key.into_iter().collect();
3956
3957			// Sign in with the bearer key
3958			let mut sess = Session {
3959				ns: Some("test".to_string()),
3960				db: Some("test".to_string()),
3961				..Default::default()
3962			};
3963			let mut vars: HashMap<&str, Value> = HashMap::new();
3964			vars.insert("key", key.into());
3965			let res = db_access(
3966				&ds,
3967				&mut sess,
3968				"test".to_string(),
3969				"test".to_string(),
3970				"api".to_string(),
3971				vars.into(),
3972			)
3973			.await;
3974
3975			match res {
3976				Err(Error::InvalidAuth) => {} // ok
3977				res => panic!(
3978					"Expected a generic authentication error, but instead received: {:?}",
3979					res
3980				),
3981			}
3982		}
3983
3984		// Test with incorrect bearer key value
3985		{
3986			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
3987				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
3988			);
3989			let sess = Session::owner().with_ns("test").with_db("test");
3990			let res = ds
3991				.execute(
3992					r#"
3993					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
3994						DURATION FOR SESSION 2h
3995					;
3996					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
3997					"#,
3998					&sess,
3999					None,
4000				)
4001				.await
4002				.unwrap();
4003
4004			// Get the bearer key from grant
4005			let result = if let Ok(res) = &res.last().unwrap().result {
4006				res.clone()
4007			} else {
4008				panic!("Unable to retrieve bearer key grant");
4009			};
4010			let grant = result
4011				.coerce_to_object()
4012				.unwrap()
4013				.get("grant")
4014				.unwrap()
4015				.clone()
4016				.coerce_to_object()
4017				.unwrap();
4018			let valid_key = grant.get("key").unwrap().clone().as_string();
4019
4020			// Replace a character from the key value
4021			let mut invalid_key: Vec<char> = valid_key.chars().collect();
4022			invalid_key[valid_key.len() - 2] = '_';
4023			let key: String = invalid_key.into_iter().collect();
4024
4025			// Sign in with the bearer key
4026			let mut sess = Session {
4027				ns: Some("test".to_string()),
4028				db: Some("test".to_string()),
4029				..Default::default()
4030			};
4031			let mut vars: HashMap<&str, Value> = HashMap::new();
4032			vars.insert("key", key.into());
4033			let res = db_access(
4034				&ds,
4035				&mut sess,
4036				"test".to_string(),
4037				"test".to_string(),
4038				"api".to_string(),
4039				vars.into(),
4040			)
4041			.await;
4042
4043			match res {
4044				Err(Error::InvalidAuth) => {} // ok
4045				res => panic!(
4046					"Expected a generic authentication error, but instead received: {:?}",
4047					res
4048				),
4049			}
4050		}
4051
4052		// Test that only the key hash is stored
4053		{
4054			let ds = Datastore::new("memory").await.unwrap().with_capabilities(
4055				Capabilities::default().with_experimental(ExperimentalTarget::BearerAccess.into()),
4056			);
4057			let sess = Session::owner().with_ns("test").with_db("test");
4058			let res = ds
4059				.execute(
4060					r#"
4061					DEFINE ACCESS api ON DATABASE TYPE BEARER FOR RECORD
4062						DURATION FOR SESSION 2h
4063					;
4064					ACCESS api ON DATABASE GRANT FOR RECORD user:test;
4065					"#,
4066					&sess,
4067					None,
4068				)
4069				.await
4070				.unwrap();
4071
4072			// Get the bearer key from grant
4073			let result = if let Ok(res) = &res.last().unwrap().result {
4074				res.clone()
4075			} else {
4076				panic!("Unable to retrieve bearer key grant");
4077			};
4078			let grant = result
4079				.coerce_to_object()
4080				.unwrap()
4081				.get("grant")
4082				.unwrap()
4083				.clone()
4084				.coerce_to_object()
4085				.unwrap();
4086			let id = grant.get("id").unwrap().clone().as_string();
4087			let key = grant.get("key").unwrap().clone().as_string();
4088
4089			// Test that returned key is in plain text
4090			let ok = Regex::new(r"surreal-bearer-[a-zA-Z0-9]{12}-[a-zA-Z0-9]{24}").unwrap();
4091			assert!(ok.is_match(&key), "Output '{}' doesn't match regex '{}'", key, ok);
4092
4093			// Get the stored bearer grant
4094			let tx = ds.transaction(Read, Optimistic).await.unwrap().enclose();
4095			let grant = tx.get_db_access_grant("test", "test", "api", &id).await.unwrap();
4096			let key = match &grant.grant {
4097				access::Grant::Bearer(grant) => grant.key.clone(),
4098				_ => panic!("Incorrect grant type returned, expected a bearer grant"),
4099			};
4100			tx.cancel().await.unwrap();
4101
4102			// Test that the returned key is a SHA-256 hash
4103			let ok = Regex::new(r"[0-9a-f]{64}").unwrap();
4104			assert!(ok.is_match(&key), "Output '{}' doesn't match regex '{}'", key, ok);
4105		}
4106	}
4107
4108	#[tokio::test]
4109	async fn test_signin_nonexistent_role() {
4110		use crate::iam::Error as IamError;
4111		use crate::sql::{
4112			statements::{define::DefineStatement, DefineUserStatement},
4113			user::UserDuration,
4114			Base, Statement,
4115		};
4116		let test_levels = vec![
4117			TestLevel {
4118				level: "ROOT",
4119				ns: None,
4120				db: None,
4121			},
4122			TestLevel {
4123				level: "NS",
4124				ns: Some("test"),
4125				db: None,
4126			},
4127			TestLevel {
4128				level: "DB",
4129				ns: Some("test"),
4130				db: Some("test"),
4131			},
4132		];
4133
4134		for level in &test_levels {
4135			let ds = Datastore::new("memory").await.unwrap();
4136			let sess = Session::owner().with_ns("test").with_db("test");
4137
4138			let base = match level.level {
4139				"ROOT" => Base::Root,
4140				"NS" => Base::Ns,
4141				"DB" => Base::Db,
4142				_ => panic!("Unsupported level"),
4143			};
4144
4145			let user = DefineUserStatement {
4146				base,
4147				name: "user".into(),
4148				// This is the Argon2id hash for "pass" with a random salt.
4149				hash: "$argon2id$v=19$m=16,t=2,p=1$VUlHTHVOYjc5d0I1dGE3OQ$sVtmRNH+Xtiijk0uXL2+4w"
4150					.to_string(),
4151				code: "dummy".to_string(),
4152				roles: vec!["nonexistent".into()],
4153				duration: UserDuration::default(),
4154				comment: None,
4155				if_not_exists: false,
4156				overwrite: false,
4157			};
4158
4159			// Use pre-parsed definition, which bypasses the existent role check during parsing.
4160			ds.process(Statement::Define(DefineStatement::User(user)).into(), &sess, None)
4161				.await
4162				.unwrap();
4163
4164			let mut sess = Session {
4165				ns: level.ns.map(String::from),
4166				db: level.db.map(String::from),
4167				..Default::default()
4168			};
4169
4170			// Sign in using the newly defined user.
4171			let res = match level.level {
4172				"ROOT" => root_user(&ds, &mut sess, "user".to_string(), "pass".to_string()).await,
4173				"NS" => {
4174					ns_user(
4175						&ds,
4176						&mut sess,
4177						level.ns.unwrap().to_string(),
4178						"user".to_string(),
4179						"pass".to_string(),
4180					)
4181					.await
4182				}
4183				"DB" => {
4184					db_user(
4185						&ds,
4186						&mut sess,
4187						level.ns.unwrap().to_string(),
4188						level.db.unwrap().to_string(),
4189						"user".to_string(),
4190						"pass".to_string(),
4191					)
4192					.await
4193				}
4194				_ => panic!("Unsupported level"),
4195			};
4196
4197			match res {
4198				Err(Error::IamError(IamError::InvalidRole(_))) => {} // ok
4199				res => {
4200					panic!("Expected an invalid role IAM error, but instead received: {:?}", res)
4201				}
4202			}
4203		}
4204	}
4205}