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 vars.validate_computed()?;
55 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 match (ns, db, ac) {
61 (Some(ns), Some(db), Some(ac)) => {
63 let ns = ns.to_raw_string();
65 let db = db.to_raw_string();
66 let ac = ac.to_raw_string();
67 super::signin::db_access(kvs, session, ns, db, ac, vars).await
69 }
70 (Some(ns), Some(db), None) => {
72 let user = vars.get("user");
74 let pass = vars.get("pass");
75 match (user, pass) {
77 (Some(user), Some(pass)) => {
79 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 super::signin::db_user(kvs, session, ns, db, user, pass).await
86 }
87 _ => Err(Error::MissingUserOrPass),
88 }
89 }
90 (Some(ns), None, Some(ac)) => {
92 let ns = ns.to_raw_string();
94 let ac = ac.to_raw_string();
95 super::signin::ns_access(kvs, session, ns, ac, vars).await
97 }
98 (Some(ns), None, None) => {
100 let user = vars.get("user");
102 let pass = vars.get("pass");
103 match (user, pass) {
105 (Some(user), Some(pass)) => {
107 let ns = ns.to_raw_string();
109 let user = user.to_raw_string();
110 let pass = pass.to_raw_string();
111 super::signin::ns_user(kvs, session, ns, user, pass).await
113 }
114 _ => Err(Error::MissingUserOrPass),
115 }
116 }
117 (None, None, None) => {
119 let user = vars.get("user");
121 let pass = vars.get("pass");
122 match (user, pass) {
124 (Some(user), Some(pass)) => {
126 let user = user.to_raw_string();
128 let pass = pass.to_raw_string();
129 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 let tx = kvs.transaction(Read, Optimistic).await?;
149 let access = tx.get_db_access(&ns, &db, &ac).await;
151 tx.cancel().await?;
153 match access {
155 Ok(av) => {
156 match av.kind.clone() {
161 AccessType::Record(at) => {
162 let iss = match &at.jwt.issue {
164 Some(iss) => iss.clone(),
165 _ => return Err(Error::AccessMethodMismatch),
166 };
167 if let Some(bearer) = &at.bearer {
169 if let Some(key) = vars.get("refresh") {
171 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 Some(val) => {
187 let vars = Some(vars.0);
189 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 match kvs.evaluate(val, &sess, vars).await {
195 Ok(val) => {
197 match val.record() {
198 Some(mut rid) => {
200 let key = config(iss.alg, &iss.key)?;
202 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 if let Some(au) = &av.authenticate {
217 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 let refresh = match &at.bearer {
228 Some(_) => {
229 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 trace!(
252 "Signing in to database with access method `{}`",
253 ac
254 );
255 let enc =
257 encode(&Header::new(iss.alg.into()), &claims, &key);
258 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 match enc {
272 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 Error::Thrown(_) => Err(e),
286 Error::Tx(_) | Error::TxFailure | Error::TxRetryable => {
289 debug!("Unexpected error found while executing a SIGNIN clause: {e}");
290 Err(Error::UnexpectedAuth)
291 }
292 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 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 let key = EncodingKey::from_secret(u.code.as_ref());
335 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 trace!("Signing in to database `{ns}/{db}`");
349 let enc = encode(&HEADER, &val, &key);
351 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 match enc {
359 Ok(tk) => Ok(SigninData {
361 token: tk,
362 refresh: None,
363 }),
364 _ => Err(Error::TokenMakingFailed),
365 }
366 }
367 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 let tx = kvs.transaction(Read, Optimistic).await?;
384 let access = tx.get_ns_access(&ns, &ac).await;
386 tx.cancel().await?;
388 match access {
390 Ok(av) => {
391 match av.kind.clone() {
393 AccessType::Bearer(at) => {
394 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 let key = EncodingKey::from_secret(u.code.as_ref());
420 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 trace!("Signing in to namespace `{ns}`");
433 let enc = encode(&HEADER, &val, &key);
435 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 match enc {
442 Ok(tk) => Ok(SigninData {
444 token: tk,
445 refresh: None,
446 }),
447 _ => Err(Error::TokenMakingFailed),
448 }
449 }
450 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 let key = EncodingKey::from_secret(u.code.as_ref());
470 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 trace!("Signing in as root");
482 let enc = encode(&HEADER, &val, &key);
484 session.tk = Some(val.into());
486 session.exp = expiration(u.duration.session)?;
487 session.au = Arc::new((&u, Level::Root).try_into()?);
488 match enc {
490 Ok(tk) => Ok(SigninData {
492 token: tk,
493 refresh: None,
494 }),
495 _ => Err(Error::TokenMakingFailed),
496 }
497 }
498 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 let tx = kvs.transaction(Read, Optimistic).await?;
514 let access = tx.get_root_access(&ac).await;
516 tx.cancel().await?;
518 match access {
520 Ok(av) => {
521 match av.kind.clone() {
523 AccessType::Bearer(at) => {
524 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 if !kvs.get_capabilities().allows_experimental(&ExperimentalTarget::BearerAccess) {
550 debug!("Error attempting to authenticate with disabled bearer access feature");
552 return Err(Error::InvalidAuth);
553 }
554 let iss = match &at.jwt.issue {
556 Some(iss) => iss.clone(),
557 _ => return Err(Error::AccessMethodMismatch),
558 };
559 let kid = validate_grant_bearer(&key)?;
561 let tx = kvs.transaction(Read, Optimistic).await?;
563 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 Error::InvalidAuth
574 })?;
575 tx.cancel().await?;
577 verify_grant_bearer(&gr, key)?;
579 let roles = if let access::Subject::User(user) = &gr.subject {
581 let tx = kvs.transaction(Read, Optimistic).await?;
583 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 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 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 Error::InvalidAuth
599 }),
600 (None, Some(_)) => return Err(Error::NsEmpty),
601 }?;
602 tx.cancel().await?;
604 user.roles.clone()
605 } else {
606 vec![]
607 };
608 let key = config(iss.alg, &iss.key)?;
610 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 if let Some(au) = &av.authenticate {
632 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 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_refresh_token_record(kvs, gr.id.clone(), gr.ac.clone(), ns, db)
652 .await?;
653 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 trace!("Signing in to database with bearer access method `{}`", av.name);
675 let enc = encode(&Header::new(iss.alg.into()), &claims, &key);
677 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 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 access_type::BearerAccessType::from_str(parts[1])?;
727 let kid = parts[2];
729 if kid.len() != access::GRANT_BEARER_ID_LENGTH {
731 return Err(Error::AccessGrantBearerInvalid);
732 };
733 let key = parts[3];
735 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 match (&gr.expiration, &gr.revocation) {
749 (None, None) => {}
750 (Some(exp), None) => {
751 if exp < &Datetime::default() {
752 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 match &gr.grant {
765 access::Grant::Bearer(bearer) => {
766 let mut hasher = Sha256::new();
768 hasher.update(key);
769 let hash = hasher.finalize();
770 let hash_hex = format!("{hash:x}");
771 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 {
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 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 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 let exp = sess.exp.unwrap();
868 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 {
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 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 {
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 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 {
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 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 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 let exp = sess.exp.unwrap();
1049 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 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 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 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 let exp = sess.exp.unwrap();
1092 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 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) => {} Err(e) => panic!("Expected InvalidAuth, but got: {e}"),
1115 }
1116 }
1117 {
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 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 std::thread::sleep(Duration::seconds(2).to_std().unwrap());
1171 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 match res {
1185 Ok(data) => panic!("Unexpected successful signin: {:?}", data),
1186 Err(Error::InvalidAuth) => {} Err(e) => panic!("Expected InvalidAuth, but got: {e}"),
1188 }
1189 }
1190 {
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 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 let id = refresh.split("-").collect::<Vec<&str>>()[2];
1247
1248 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 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 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 {
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 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 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 let exp = sess.exp.unwrap();
1372 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 if let Ok(sd) = res {
1384 let val = Validation::new(Algorithm::RS256);
1386 let token_data = decode::<Claims>(
1388 &sd.token,
1389 &DecodingKey::from_rsa_pem(public_key.as_ref()).unwrap(),
1390 &val,
1391 )
1392 .unwrap();
1393 assert_eq!(token_data.header.alg, Algorithm::RS256);
1395 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 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 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 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 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 if let Ok(sd) = res {
1593 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 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 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 {
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 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 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 let exp = sess.exp.unwrap();
1697 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 {
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 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 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 let exp = sess.exp.unwrap();
1792 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 {
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 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" => {} res => panic!(
1852 "Expected authentication to failed due to user not being enabled, but instead received: {:?}",
1853 res
1854 ),
1855 }
1856 }
1857
1858 {
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 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) => {} 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 {
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 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 => {} e => panic!("Expected authentication to return an UnexpectedAuth error, but insted got: {e}")
1986 }
1987 (Ok(_), Err(e2)) => match &e2 {
1988 Error::UnexpectedAuth => {} e => panic!("Expected authentication to return an UnexpectedAuth error, but insted got: {e}")
1990 }
1991 }
1992 }
1993
1994 {
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 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 => {} e => panic!("Expected authentication to return an UnexpectedAuth error, but insted got: {e}")
2062 }
2063 (Ok(_), Err(e2)) => match &e2 {
2064 Error::UnexpectedAuth => {} 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 {
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 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 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 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 assert!(
2189 !sess.au.has_role(Role::Viewer),
2190 "Auth user expected to not have Viewer role"
2191 );
2192 assert!(
2193 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 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 {
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 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 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 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 assert!(
2306 !sess.au.has_role(Role::Viewer),
2307 "Auth user expected to not have Viewer role"
2308 );
2309 assert!(
2310 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 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 {
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 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 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 {
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 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 std::thread::sleep(Duration::seconds(2).to_std().unwrap());
2461
2462 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) => {} res => panic!(
2499 "Expected a generic authentication error, but instead received: {:?}",
2500 res
2501 ),
2502 }
2503 }
2504
2505 {
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 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 let kid = key.split("-").collect::<Vec<&str>>()[2];
2548
2549 ds.execute(
2551 &format!("ACCESS api ON {} REVOKE GRANT {kid}", level.level),
2552 &sess,
2553 None,
2554 )
2555 .await
2556 .unwrap();
2557
2558 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) => {} res => panic!(
2595 "Expected a generic authentication error, but instead received: {:?}",
2596 res
2597 ),
2598 }
2599 }
2600
2601 {
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 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 ds.execute(format!("REMOVE ACCESS api ON {}", level.level).as_str(), &sess, None)
2644 .await
2645 .unwrap();
2646
2647 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) => {} res => panic!(
2684 "Expected an access method not found error, but instead received: {:?}",
2685 res
2686 ),
2687 }
2688 }
2689
2690 {
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 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 let mut sess = Session {
2733 ns: level.ns.map(String::from),
2734 db: level.db.map(String::from),
2735 ..Default::default()
2736 };
2737
2738 let vars: HashMap<&str, Value> = HashMap::new();
2740 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) => {} res => panic!(
2771 "Expected a missing key authentication error, but instead received: {:?}",
2772 res
2773 ),
2774 }
2775 }
2776
2777 {
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 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 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 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) => {} res => panic!(
2860 "Expected an invalid key authentication error, but instead received: {:?}",
2861 res
2862 ),
2863 }
2864 }
2865
2866 {
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 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 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 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) => {} res => panic!(
2949 "Expected an invalid key authentication error, but instead received: {:?}",
2950 res
2951 ),
2952 }
2953 }
2954
2955 {
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 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 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 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) => {} res => panic!(
3038 "Expected a generic authentication error, but instead received: {:?}",
3039 res
3040 ),
3041 }
3042 }
3043
3044 {
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 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 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 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) => {} res => panic!(
3127 "Expected a generic authentication error, but instead received: {:?}",
3128 res
3129 ),
3130 }
3131 }
3132
3133 {
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 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 assert!(
3177 plain_text_regex.is_match(&key),
3178 "Output '{}' doesn't match regex '{}'",
3179 key,
3180 plain_text_regex
3181 );
3182
3183 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 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 {
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 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 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 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 let exp = sess.exp.unwrap();
3281 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 {
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 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 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 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 let exp = sess.exp.unwrap();
3357 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 {
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 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 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 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 let exp = sess.exp.unwrap();
3436 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 {
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 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 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 {
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 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 std::thread::sleep(Duration::seconds(2).to_std().unwrap());
3551
3552 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) => {} res => panic!(
3573 "Expected a generic authentication error, but instead received: {:?}",
3574 res
3575 ),
3576 }
3577 }
3578
3579 {
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 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 let kid = key.split("-").collect::<Vec<&str>>()[2];
3617
3618 ds.execute(&format!("ACCESS api ON DATABASE REVOKE GRANT {kid}"), &sess, None)
3620 .await
3621 .unwrap();
3622
3623 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) => {} res => panic!(
3644 "Expected a generic authentication error, but instead received: {:?}",
3645 res
3646 ),
3647 }
3648 }
3649
3650 {
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 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 ds.execute("REMOVE ACCESS api ON DATABASE", &sess, None).await.unwrap();
3688
3689 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) => {} res => panic!(
3710 "Expected an access method not found error, but instead received: {:?}",
3711 res
3712 ),
3713 }
3714 }
3715
3716 {
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 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 let mut sess = Session {
3754 ns: Some("test".to_string()),
3755 db: Some("test".to_string()),
3756 ..Default::default()
3757 };
3758 let vars: HashMap<&str, Value> = HashMap::new();
3760 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) => {} res => panic!(
3774 "Expected a missing key authentication error, but instead received: {:?}",
3775 res
3776 ),
3777 }
3778 }
3779
3780 {
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 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 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 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) => {} res => panic!(
3842 "Expected an invalid key authentication error, but instead received: {:?}",
3843 res
3844 ),
3845 }
3846 }
3847
3848 {
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 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 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 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) => {} res => panic!(
3910 "Expected an invalid key authentication error, but instead received: {:?}",
3911 res
3912 ),
3913 }
3914 }
3915
3916 {
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 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 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 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) => {} res => panic!(
3978 "Expected a generic authentication error, but instead received: {:?}",
3979 res
3980 ),
3981 }
3982 }
3983
3984 {
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 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 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 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) => {} res => panic!(
4046 "Expected a generic authentication error, but instead received: {:?}",
4047 res
4048 ),
4049 }
4050 }
4051
4052 {
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 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 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 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 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 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 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 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(_))) => {} res => {
4200 panic!("Expected an invalid role IAM error, but instead received: {:?}", res)
4201 }
4202 }
4203 }
4204 }
4205}