-
Notifications
You must be signed in to change notification settings - Fork 67
[2/n] Silo-level max device token TTL #8214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
b03b0a0
791d946
a4456aa
072e934
a82ad21
ac70bc4
ece0895
09df45d
7dd0f13
329fe8e
efa26e7
b520a82
5d8f01f
4dd9321
df0fae8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| use chrono::{DateTime, Utc}; | ||
| use nexus_db_schema::schema::silo_auth_settings; | ||
| use nexus_types::external_api::{params, views}; | ||
| use serde::{Deserialize, Serialize}; | ||
| use uuid::Uuid; | ||
|
|
||
| #[derive( | ||
| Queryable, | ||
| Insertable, | ||
| Debug, | ||
| Clone, | ||
| Selectable, | ||
| Serialize, | ||
| Deserialize, | ||
| AsChangeset, | ||
| )] | ||
| #[diesel(table_name = silo_auth_settings)] | ||
| pub struct SiloAuthSettings { | ||
| pub silo_id: Uuid, | ||
| pub time_created: DateTime<Utc>, | ||
| pub time_modified: DateTime<Utc>, | ||
|
|
||
| /// Max token lifetime in seconds. Null means no max: users can create | ||
| /// tokens that never expire. | ||
| pub device_token_max_ttl_seconds: Option<i64>, | ||
| } | ||
|
|
||
| impl SiloAuthSettings { | ||
| pub fn new(silo_id: Uuid) -> Self { | ||
| Self { | ||
| silo_id, | ||
| time_created: Utc::now(), | ||
| time_modified: Utc::now(), | ||
| device_token_max_ttl_seconds: None, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl From<SiloAuthSettings> for views::SiloAuthSettings { | ||
| fn from(silo_auth_settings: SiloAuthSettings) -> Self { | ||
| Self { | ||
| silo_id: silo_auth_settings.silo_id, | ||
| device_token_max_ttl_seconds: silo_auth_settings | ||
| .device_token_max_ttl_seconds, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Describes a set of updates for the [`SiloAuthSettings`] model. | ||
| #[derive(AsChangeset)] | ||
| #[diesel(table_name = silo_auth_settings)] | ||
| pub struct SiloAuthSettingsUpdate { | ||
| // Needs to be double Option so we can set a value of null in the DB by | ||
| // passing Some(None). None by itself is ignored by Diesel. | ||
| pub device_token_max_ttl_seconds: Option<Option<i64>>, | ||
| pub time_modified: DateTime<Utc>, | ||
| } | ||
|
|
||
| impl From<params::SiloAuthSettingsUpdate> for SiloAuthSettingsUpdate { | ||
| fn from(params: params::SiloAuthSettingsUpdate) -> Self { | ||
| Self { | ||
| device_token_max_ttl_seconds: Some( | ||
| params.device_token_max_ttl_seconds.map(|ttl| ttl.get().into()), | ||
| ), | ||
| time_modified: Utc::now(), | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| use super::DataStore; | ||
| use crate::authz; | ||
| use crate::context::OpContext; | ||
| use async_bb8_diesel::AsyncRunQueryDsl; | ||
| use diesel::prelude::*; | ||
| use nexus_db_errors::ErrorHandler; | ||
| use nexus_db_errors::public_error_from_diesel; | ||
| use nexus_db_lookup::DbConnection; | ||
| use nexus_db_model::SiloAuthSettings; | ||
| use nexus_db_model::SiloAuthSettingsUpdate; | ||
| use omicron_common::api::external::DeleteResult; | ||
| use omicron_common::api::external::Error; | ||
| use omicron_common::api::external::ResourceType; | ||
| use omicron_common::api::external::UpdateResult; | ||
|
|
||
| // Directly modeled on settings query functions. | ||
|
|
||
| impl DataStore { | ||
| /// Creates new settings for a silo. This is grouped with silo creation | ||
| /// and shouldn't be called outside of that flow. | ||
| /// | ||
| /// An authz check _cannot_ be performed here because the authz initialization | ||
| /// isn't complete and will lead to a db deadlock. | ||
| /// | ||
| /// See <https://github.com/oxidecomputer/omicron/blob/07eb7dafc20e35e44edf429fcbb759cbb33edd5f/nexus/db-queries/src/db/datastore/rack.rs#L407-L410> | ||
| pub async fn silo_auth_settings_create( | ||
| &self, | ||
| conn: &async_bb8_diesel::Connection<DbConnection>, | ||
| authz_silo: &authz::Silo, | ||
| settings: SiloAuthSettings, | ||
| ) -> Result<(), Error> { | ||
| let silo_id = authz_silo.id(); | ||
| use nexus_db_schema::schema::silo_auth_settings; | ||
|
|
||
| diesel::insert_into(silo_auth_settings::table) | ||
| .values(settings) | ||
| .execute_async(conn) | ||
| .await | ||
| .map_err(|e| { | ||
| public_error_from_diesel( | ||
| e, | ||
| ErrorHandler::Conflict( | ||
| ResourceType::SiloAuthSettings, | ||
| &silo_id.to_string(), | ||
| ), | ||
| ) | ||
| }) | ||
| .map(|_| ()) | ||
| } | ||
|
|
||
| pub async fn silo_auth_settings_delete( | ||
| &self, | ||
| opctx: &OpContext, | ||
| conn: &async_bb8_diesel::Connection<DbConnection>, | ||
| authz_silo: &authz::Silo, | ||
| ) -> DeleteResult { | ||
| // Given that the settings right now are somewhat of an extension of the | ||
| // Silo we just check for delete permission on the silo itself. | ||
| opctx.authorize(authz::Action::Delete, authz_silo).await?; | ||
david-crespo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| use nexus_db_schema::schema::silo_auth_settings; | ||
| diesel::delete(silo_auth_settings::table) | ||
| .filter(silo_auth_settings::silo_id.eq(authz_silo.id())) | ||
| .execute_async(conn) | ||
| .await | ||
| .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))?; | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| pub async fn silo_auth_settings_update( | ||
| &self, | ||
| opctx: &OpContext, | ||
| authz_silo: &authz::Silo, | ||
| updates: SiloAuthSettingsUpdate, | ||
| ) -> UpdateResult<SiloAuthSettings> { | ||
| opctx.authorize(authz::Action::Modify, authz_silo).await?; | ||
| use nexus_db_schema::schema::silo_auth_settings::dsl; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit, not important: seems like we ought to be able to import this globally in this module...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For whatever reason we just do this in all the datastore functions. Kind of a cargo cult thing. The real reason to do it this way would be if if we imported * from the DSL like the examples on the Diesel site do. |
||
| let silo_id = authz_silo.id(); | ||
| diesel::update(dsl::silo_auth_settings) | ||
| .filter(dsl::silo_id.eq(silo_id)) | ||
| .set(updates) | ||
| .returning(SiloAuthSettings::as_returning()) | ||
| .get_result_async(&*self.pool_connection_authorized(opctx).await?) | ||
| .await | ||
| .map_err(|e| { | ||
| public_error_from_diesel( | ||
| e, | ||
| ErrorHandler::Conflict( | ||
| ResourceType::SiloAuthSettings, | ||
| &silo_id.to_string(), | ||
| ), | ||
| ) | ||
| }) | ||
| } | ||
|
|
||
| pub async fn silo_auth_settings_view( | ||
| &self, | ||
| opctx: &OpContext, | ||
| authz_silo: &authz::Silo, | ||
| ) -> Result<SiloAuthSettings, Error> { | ||
| // Works for everyone when making a token because everyone can read | ||
| // their own silo. Operators looking at silo settings will have silo | ||
| // read on all silos. | ||
| opctx.authorize(authz::Action::Read, authz_silo).await?; | ||
|
|
||
| use nexus_db_schema::schema::silo_auth_settings::dsl; | ||
| dsl::silo_auth_settings | ||
| .filter(dsl::silo_id.eq(authz_silo.id())) | ||
| .first_async(&*self.pool_connection_authorized(opctx).await?) | ||
| .await | ||
| .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server)) | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.