Ensure scope SIGNUP and SIGNIN works with guest access disabled (#2663)

This commit is contained in:
Tobie Morgan Hitchcock 2023-09-10 11:41:28 +01:00 committed by GitHub
parent b83b9d3e3e
commit 9f33d5dc27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 9 deletions

View file

@ -116,9 +116,9 @@ pub async fn sc(
// Setup the query params // Setup the query params
let vars = Some(vars.0); let vars = Some(vars.0);
// Setup the system session for finding the signin record // Setup the system session for finding the signin record
let sess = Session::viewer().with_ns(&ns).with_db(&db); let sess = Session::editor().with_ns(&ns).with_db(&db);
// Compute the value with the params // Compute the value with the params
match kvs.compute(val, &sess, vars).await { match kvs.evaluate(val, &sess, vars).await {
// The signin value succeeded // The signin value succeeded
Ok(val) => match val.record() { Ok(val) => match val.record() {
// There is a record returned // There is a record returned

View file

@ -59,7 +59,7 @@ pub async fn sc(
// Setup the system session for creating the signup record // Setup the system session for creating the signup record
let sess = Session::editor().with_ns(&ns).with_db(&db); let sess = Session::editor().with_ns(&ns).with_db(&db);
// Compute the value with the params // Compute the value with the params
match kvs.compute(val, &sess, vars).await { match kvs.evaluate(val, &sess, vars).await {
// The signin value succeeded // The signin value succeeded
Ok(val) => match val.record() { Ok(val) => match val.record() {
// There is a record returned // There is a record returned

View file

@ -787,7 +787,7 @@ impl Datastore {
vars: Variables, vars: Variables,
) -> Result<Vec<Response>, Error> { ) -> Result<Vec<Response>, Error> {
// Check if anonymous actors can execute queries when auth is enabled // Check if anonymous actors can execute queries when auth is enabled
// TODO(sgirones): Check this as part of the authoritzation layer // TODO(sgirones): Check this as part of the authorisation layer
if self.auth_enabled && sess.au.is_anon() && !self.capabilities.allows_guest_access() { if self.auth_enabled && sess.au.is_anon() && !self.capabilities.allows_guest_access() {
return Err(IamError::NotAllowed { return Err(IamError::NotAllowed {
actor: "anonymous".to_string(), actor: "anonymous".to_string(),
@ -803,8 +803,8 @@ impl Datastore {
.with_db(sess.db()) .with_db(sess.db())
.with_live(sess.live()) .with_live(sess.live())
.with_auth(sess.au.clone()) .with_auth(sess.au.clone())
.with_auth_enabled(self.auth_enabled) .with_strict(self.strict)
.with_strict(self.strict); .with_auth_enabled(self.auth_enabled);
// Create a new query executor // Create a new query executor
let mut exe = Executor::new(self); let mut exe = Executor::new(self);
// Create a default context // Create a default context
@ -852,7 +852,7 @@ impl Datastore {
vars: Variables, vars: Variables,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Check if anonymous actors can compute values when auth is enabled // Check if anonymous actors can compute values when auth is enabled
// TODO(sgirones): Check this as part of the authoritzation layer // TODO(sgirones): Check this as part of the authorisation layer
if self.auth_enabled && !self.capabilities.allows_guest_access() { if self.auth_enabled && !self.capabilities.allows_guest_access() {
return Err(IamError::NotAllowed { return Err(IamError::NotAllowed {
actor: "anonymous".to_string(), actor: "anonymous".to_string(),
@ -868,8 +868,77 @@ impl Datastore {
.with_db(sess.db()) .with_db(sess.db())
.with_live(sess.live()) .with_live(sess.live())
.with_auth(sess.au.clone()) .with_auth(sess.au.clone())
.with_auth_enabled(self.auth_enabled) .with_strict(self.strict)
.with_strict(self.strict); .with_auth_enabled(self.auth_enabled);
// Create a default context
let mut ctx = Context::default();
// Set context capabilities
ctx.add_capabilities(self.capabilities.clone());
// Set the global query timeout
if let Some(timeout) = self.query_timeout {
ctx.add_timeout(timeout);
}
// Setup the notification channel
if let Some(channel) = &self.notification_channel {
ctx.add_notifications(Some(&channel.0));
}
// Start an execution context
let ctx = sess.context(ctx);
// Store the query variables
let ctx = vars.attach(ctx)?;
// Start a new transaction
let txn = self.transaction(val.writeable(), false).await?.enclose();
// Compute the value
let res = val.compute(&ctx, &opt, &txn, None).await;
// Store any data
match (res.is_ok(), val.writeable()) {
// If the compute was successful, then commit if writeable
(true, true) => txn.lock().await.commit().await?,
// Cancel if the compute was an error, or if readonly
(_, _) => txn.lock().await.cancel().await?,
};
// Return result
res
}
/// Evaluates a SQL [`Value`] without checking authenticating config
/// This is used in very specific cases, where we do not need to check
/// whether authentication is enabled, or guest access is disabled.
/// For example, this is used when processing a SCOPE SIGNUP or SCOPE
/// SIGNIN clause, which still needs to work without guest access.
///
/// ```rust,no_run
/// use surrealdb::kvs::Datastore;
/// use surrealdb::err::Error;
/// use surrealdb::dbs::Session;
/// use surrealdb::sql::Future;
/// use surrealdb::sql::Value;
///
/// #[tokio::main]
/// async fn main() -> Result<(), Error> {
/// let ds = Datastore::new("memory").await?;
/// let ses = Session::owner();
/// let val = Value::Future(Box::new(Future::from(Value::Bool(true))));
/// let res = ds.evaluate(val, &ses, None).await?;
/// Ok(())
/// }
/// ```
#[instrument(level = "debug", skip_all)]
pub async fn evaluate(
&self,
val: Value,
sess: &Session,
vars: Variables,
) -> Result<Value, Error> {
// Create a new query options
let opt = Options::default()
.with_id(self.id.0)
.with_ns(sess.ns())
.with_db(sess.db())
.with_live(sess.live())
.with_auth(sess.au.clone())
.with_strict(self.strict)
.with_auth_enabled(self.auth_enabled);
// Create a default context // Create a default context
let mut ctx = Context::default(); let mut ctx = Context::default();
// Set context capabilities // Set context capabilities