surrealdb_core/iam/
auth.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::sql::statements::{DefineAccessStatement, DefineUserStatement};
use revision::revisioned;
use serde::{Deserialize, Serialize};

use super::{is_allowed, Action, Actor, Error, Level, Resource, Role};

/// Specifies the current authentication for the datastore execution context.
#[revisioned(revision = 1)]
#[derive(Clone, Default, Debug, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[non_exhaustive]
pub struct Auth {
	actor: Actor,
}

impl Auth {
	pub fn new(actor: Actor) -> Self {
		Self {
			actor,
		}
	}

	pub fn id(&self) -> &str {
		self.actor.id()
	}

	/// Return current authentication level
	pub fn level(&self) -> &Level {
		self.actor.level()
	}

	/// Check if the current auth is anonymous
	pub fn is_anon(&self) -> bool {
		matches!(self.level(), Level::No)
	}

	/// Check if the current level is Root
	pub fn is_root(&self) -> bool {
		matches!(self.level(), Level::Root)
	}

	/// Check if the current level is Namespace
	pub fn is_ns(&self) -> bool {
		matches!(self.level(), Level::Namespace(_))
	}

	/// Check if the current level is Database
	pub fn is_db(&self) -> bool {
		matches!(self.level(), Level::Database(_, _))
	}

	/// Check if the current level is Record
	pub fn is_record(&self) -> bool {
		matches!(self.level(), Level::Record(_, _, _))
	}

	/// Check if the current level is Namespace, and the namespace matches
	pub fn is_ns_check(&self, ns: &str) -> bool {
		matches!(self.level(), Level::Namespace(n) if n.eq(ns))
	}

	/// Check if the current level is Database, and the namespace and database match
	pub fn is_db_check(&self, ns: &str, db: &str) -> bool {
		matches!(self.level(), Level::Database(n, d) if n.eq(ns) && d.eq(db))
	}

	/// System Auth helpers
	///
	/// These are not stored in the database and are used for internal operations
	/// Do not use for authentication
	pub fn for_root(role: Role) -> Self {
		Self::new(Actor::new("system_auth".into(), vec![role], Level::Root))
	}

	pub fn for_ns(role: Role, ns: &str) -> Self {
		Self::new(Actor::new("system_auth".into(), vec![role], (ns,).into()))
	}

	pub fn for_db(role: Role, ns: &str, db: &str) -> Self {
		Self::new(Actor::new("system_auth".into(), vec![role], (ns, db).into()))
	}

	pub fn for_record(rid: String, ns: &str, db: &str, ac: &str) -> Self {
		Self::new(Actor::new(rid.to_string(), vec![], (ns, db, ac).into()))
	}

	//
	// Permission checks
	//

	/// Checks if the current auth is allowed to perform an action on a given resource
	pub fn is_allowed(&self, action: Action, res: &Resource) -> Result<(), Error> {
		is_allowed(&self.actor, &action, res, None)
	}

	/// Checks if the current actor has a given role
	pub fn has_role(&self, role: Role) -> bool {
		self.actor.has_role(role)
	}

	/// Checks if the current actor has a Owner role
	pub fn has_owner_role(&self) -> bool {
		self.actor.has_owner_role()
	}

	/// Checks if the current actor has a Editor role
	pub fn has_editor_role(&self) -> bool {
		self.actor.has_editor_role()
	}

	/// Checks if the current actor has a Viewer role
	pub fn has_viewer_role(&self) -> bool {
		self.actor.has_viewer_role()
	}
}

impl std::convert::TryFrom<(&DefineUserStatement, Level)> for Auth {
	type Error = Error;
	fn try_from(val: (&DefineUserStatement, Level)) -> Result<Self, Self::Error> {
		Ok(Self::new((val.0, val.1).try_into()?))
	}
}

impl std::convert::From<(&DefineAccessStatement, Level)> for Auth {
	fn from(val: (&DefineAccessStatement, Level)) -> Self {
		Self::new((val.0, val.1).into())
	}
}