From a1868ac73c501ae3bcd5d628fd8ec3d46875cc03 Mon Sep 17 00:00:00 2001 From: Sean Klein Date: Fri, 31 May 2024 16:35:26 -0700 Subject: [PATCH] Rely on FakeStorage more --- nexus/auth/src/authz/context.rs | 119 ++++++++++++++++++++++ nexus/db-queries/src/db/datastore/auth.rs | 92 ----------------- 2 files changed, 119 insertions(+), 92 deletions(-) diff --git a/nexus/auth/src/authz/context.rs b/nexus/auth/src/authz/context.rs index 06d48b3f3d..59b7080fca 100644 --- a/nexus/auth/src/authz/context.rs +++ b/nexus/auth/src/authz/context.rs @@ -191,3 +191,122 @@ pub trait AuthorizedResource: oso::ToPolar + Send + Sync + 'static { /// Returns the Polar class that implements this resource fn polar_class(&self) -> oso::Class; } + +#[cfg(test)] +mod test { + use crate::authn; + use crate::authz::Action; + use crate::authz::AnyActor; + use crate::authz::Authz; + use crate::authz::Context; + use crate::authz::RoleSet; + use crate::context::OpContext; + use omicron_test_utils::dev; + use std::sync::Arc; + + use nexus_db_model::IdentityType; + use nexus_db_model::RoleAssignment; + use omicron_common::api::external::Error; + use omicron_common::api::external::ResourceType; + use uuid::Uuid; + + struct FakeStorage {} + + impl FakeStorage { + fn new() -> Arc { + Arc::new(Self {}) + } + } + + #[async_trait::async_trait] + impl crate::storage::Storage for FakeStorage { + async fn role_asgn_list_for( + &self, + _opctx: &OpContext, + _identity_type: IdentityType, + _identity_id: Uuid, + _resource_type: ResourceType, + _resource_id: Uuid, + ) -> Result, Error> { + todo!(); + } + } + + fn authz_context_for_actor( + log: &slog::Logger, + authn: authn::Context, + datastore: Arc, + ) -> Context { + let authz = Authz::new(log); + Context::new(Arc::new(authn), Arc::new(authz), datastore) + } + + #[tokio::test] + async fn test_unregistered_resource() { + let logctx = dev::test_setup_log("test_unregistered_resource"); + let datastore = FakeStorage::new(); + let opctx = OpContext::for_background( + logctx.log.new(o!()), + Arc::new(Authz::new(&logctx.log)), + authn::Context::internal_db_init(), + Arc::clone(&datastore) as Arc, + ); + + // Define a resource that we "forget" to register with Oso. + use crate::authz::AuthorizedResource; + use oso::PolarClass; + #[derive(Clone, PolarClass)] + struct UnregisteredResource; + impl AuthorizedResource for UnregisteredResource { + fn load_roles<'a, 'b, 'c, 'd, 'e>( + &'a self, + _: &'b OpContext, + _: &'c authn::Context, + _: &'d mut RoleSet, + ) -> futures::future::BoxFuture<'e, Result<(), Error>> + where + 'a: 'e, + 'b: 'e, + 'c: 'e, + 'd: 'e, + { + // authorize() shouldn't get far enough to call this. + unimplemented!(); + } + + fn on_unauthorized( + &self, + _: &Authz, + _: Error, + _: AnyActor, + _: Action, + ) -> Error { + // authorize() shouldn't get far enough to call this. + unimplemented!(); + } + + fn polar_class(&self) -> oso::Class { + Self::get_polar_class() + } + } + + // Make sure an authz check with this resource fails with a clear + // message. + let unregistered_resource = UnregisteredResource {}; + let authz_privileged = authz_context_for_actor( + &logctx.log, + authn::Context::privileged_test_user(), + Arc::clone(&datastore) as Arc, + ); + let error = authz_privileged + .authorize(&opctx, Action::Read, unregistered_resource) + .await; + println!("{:?}", error); + assert!(matches!(error, Err(Error::InternalError { + internal_message + }) if internal_message == "attempted authz check \ + on unregistered resource: \"UnregisteredResource\"")); + + logctx.cleanup_successful(); + } +} diff --git a/nexus/db-queries/src/db/datastore/auth.rs b/nexus/db-queries/src/db/datastore/auth.rs index cb1d90df5d..3b1d1d18e3 100644 --- a/nexus/db-queries/src/db/datastore/auth.rs +++ b/nexus/db-queries/src/db/datastore/auth.rs @@ -79,95 +79,3 @@ impl Storage for super::DataStore { } } } - -#[cfg(test)] -mod test { - use crate::db::DataStore; - use nexus_auth::authn; - use nexus_auth::authz::Action; - use nexus_auth::authz::AnyActor; - use nexus_auth::authz::Authz; - use nexus_auth::authz::Context; - use nexus_auth::authz::RoleSet; - use nexus_test_utils::db::test_setup_database; - use omicron_test_utils::dev; - use std::sync::Arc; - - fn authz_context_for_actor( - log: &slog::Logger, - authn: authn::Context, - datastore: Arc, - ) -> Context { - let authz = Authz::new(log); - Context::new(Arc::new(authn), Arc::new(authz), datastore) - } - - #[tokio::test] - async fn test_unregistered_resource() { - let logctx = dev::test_setup_log("test_unregistered_resource"); - let mut db = test_setup_database(&logctx.log).await; - let (opctx, datastore) = - crate::db::datastore::test_utils::datastore_test(&logctx, &db) - .await; - - // Define a resource that we "forget" to register with Oso. - use crate::context::OpContext; - use nexus_auth::authz::AuthorizedResource; - use omicron_common::api::external::Error; - use oso::PolarClass; - #[derive(Clone, PolarClass)] - struct UnregisteredResource; - impl AuthorizedResource for UnregisteredResource { - fn load_roles<'a, 'b, 'c, 'd, 'e>( - &'a self, - _: &'b OpContext, - _: &'c authn::Context, - _: &'d mut RoleSet, - ) -> futures::future::BoxFuture<'e, Result<(), Error>> - where - 'a: 'e, - 'b: 'e, - 'c: 'e, - 'd: 'e, - { - // authorize() shouldn't get far enough to call this. - unimplemented!(); - } - - fn on_unauthorized( - &self, - _: &Authz, - _: Error, - _: AnyActor, - _: Action, - ) -> Error { - // authorize() shouldn't get far enough to call this. - unimplemented!(); - } - - fn polar_class(&self) -> oso::Class { - Self::get_polar_class() - } - } - - // Make sure an authz check with this resource fails with a clear - // message. - let unregistered_resource = UnregisteredResource {}; - let authz_privileged = authz_context_for_actor( - &logctx.log, - authn::Context::privileged_test_user(), - Arc::clone(&datastore), - ); - let error = authz_privileged - .authorize(&opctx, Action::Read, unregistered_resource) - .await; - println!("{:?}", error); - assert!(matches!(error, Err(Error::InternalError { - internal_message - }) if internal_message == "attempted authz check \ - on unregistered resource: \"UnregisteredResource\"")); - - db.cleanup().await.unwrap(); - logctx.cleanup_successful(); - } -}