Skip to content

Commit 9e014d0

Browse files
committed
implicit authz on token list and delete by using current actor ID
1 parent 6ca1dd5 commit 9e014d0

File tree

4 files changed

+26
-46
lines changed

4 files changed

+26
-46
lines changed

nexus/db-queries/src/db/datastore/device_auth.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use nexus_db_schema::schema::device_access_token;
1919
use omicron_common::api::external::CreateResult;
2020
use omicron_common::api::external::DataPageParams;
2121
use omicron_common::api::external::Error;
22+
use omicron_common::api::external::InternalContext;
2223
use omicron_common::api::external::ListResultVec;
2324
use omicron_common::api::external::LookupResult;
2425
use omicron_common::api::external::LookupType;
@@ -181,19 +182,25 @@ impl DataStore {
181182
})
182183
}
183184

184-
pub async fn device_access_tokens_list(
185+
// Similar to session hard delete and silo group list, we do not do a
186+
// typical authz check, instead effectively encoding the policy here that
187+
// any user is allowed to list and delete their own tokens. When we add the
188+
// ability for silo admins to list and delete tokens from any user, we will
189+
// have to model these permissions properly in the polar policy.
190+
191+
pub async fn current_user_token_list(
185192
&self,
186193
opctx: &OpContext,
187-
authz_user: &authz::SiloUser,
188194
pagparams: &DataPageParams<'_, Uuid>,
189195
) -> ListResultVec<DeviceAccessToken> {
190-
// TODO: this authz check can't be right can it? or at least, we
191-
// should probably handle this explicitly at the policy level
192-
opctx.authorize(authz::Action::ListChildren, authz_user).await?;
196+
let &actor = opctx
197+
.authn
198+
.actor_required()
199+
.internal_context("listing current user's tokens")?;
193200

194201
use nexus_db_schema::schema::device_access_token::dsl;
195202
paginated(dsl::device_access_token, dsl::id, &pagparams)
196-
.filter(dsl::silo_user_id.eq(authz_user.id()))
203+
.filter(dsl::silo_user_id.eq(actor.actor_id()))
197204
// we don't have time_deleted on tokens. unfortunately this is not
198205
// indexed well. maybe it can be!
199206
.filter(
@@ -207,19 +214,20 @@ impl DataStore {
207214
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
208215
}
209216

210-
pub async fn device_access_token_delete(
217+
pub async fn current_user_token_delete(
211218
&self,
212219
opctx: &OpContext,
213-
authz_user: &authz::SiloUser,
214220
token_id: Uuid,
215221
) -> Result<(), Error> {
216-
// TODO: surely this is the wrong permission
217-
opctx.authorize(authz::Action::Modify, authz_user).await?;
222+
let &actor = opctx
223+
.authn
224+
.actor_required()
225+
.internal_context("deleting current user's token")?;
218226

219227
use nexus_db_schema::schema::device_access_token::dsl;
220228
let num_deleted = diesel::delete(dsl::device_access_token)
229+
.filter(dsl::silo_user_id.eq(actor.actor_id()))
221230
.filter(dsl::id.eq(token_id))
222-
.filter(dsl::silo_user_id.eq(authz_user.id()))
223231
.execute_async(&*self.pool_connection_authorized(opctx).await?)
224232
.await
225233
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))?;

nexus/src/app/device_auth.rs

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use anyhow::anyhow;
5656
use nexus_types::external_api::params::DeviceAccessTokenRequest;
5757
use nexus_types::external_api::views;
5858
use omicron_common::api::external::{
59-
CreateResult, DataPageParams, Error, InternalContext, ListResultVec,
59+
CreateResult, DataPageParams, Error, ListResultVec,
6060
};
6161

6262
use chrono::{Duration, Utc};
@@ -299,34 +299,14 @@ impl super::Nexus {
299299
opctx: &OpContext,
300300
pagparams: &DataPageParams<'_, Uuid>,
301301
) -> ListResultVec<DeviceAccessToken> {
302-
let &actor = opctx
303-
.authn
304-
.actor_required()
305-
.internal_context("loading current user to list tokens")?;
306-
let (.., authz_user) = LookupPath::new(opctx, self.datastore())
307-
.silo_user_id(actor.actor_id())
308-
.lookup_for(authz::Action::ListChildren)
309-
.await?;
310-
self.db_datastore
311-
.device_access_tokens_list(opctx, &authz_user, pagparams)
312-
.await
302+
self.db_datastore.current_user_token_list(opctx, pagparams).await
313303
}
314304

315305
pub(crate) async fn current_user_token_delete(
316306
&self,
317307
opctx: &OpContext,
318308
token_id: Uuid,
319309
) -> Result<(), Error> {
320-
let &actor = opctx
321-
.authn
322-
.actor_required()
323-
.internal_context("loading current user to delete token")?;
324-
let (.., authz_user) = LookupPath::new(opctx, self.datastore())
325-
.silo_user_id(actor.actor_id())
326-
.lookup_for(authz::Action::Modify)
327-
.await?;
328-
self.db_datastore
329-
.device_access_token_delete(opctx, &authz_user, token_id)
330-
.await
310+
self.db_datastore.current_user_token_delete(opctx, token_id).await
331311
}
332312
}

nexus/tests/integration_tests/device_auth.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use nexus_db_queries::db::fixed_data::silo::DEFAULT_SILO;
1212
use nexus_db_queries::db::identity::{Asset, Resource};
1313
use nexus_test_utils::http_testing::TestResponse;
1414
use nexus_test_utils::resource_helpers::{
15-
object_get, object_put, object_put_error,
15+
object_delete_error, object_get, object_put, object_put_error,
1616
};
1717
use nexus_test_utils::{
1818
http_testing::{AuthnMode, NexusRequest, RequestBuilder},
@@ -201,17 +201,9 @@ async fn test_device_auth_flow(cptestctx: &ControlPlaneTestContext) {
201201

202202
let token_id = tokens_unpriv_after[0].id;
203203

204-
// Test that privileged user cannot delete unpriv's token through this
205-
// endpoint, though it will probably be able to do it via a different one
204+
// Priv user cannot delete unpriv's token through this endpoint by ID
206205
let token_url = format!("/v1/me/device-tokens/{}", token_id);
207-
NexusRequest::new(
208-
RequestBuilder::new(testctx, Method::DELETE, &token_url)
209-
.expect_status(Some(StatusCode::NOT_FOUND)),
210-
)
211-
.authn_as(AuthnMode::PrivilegedUser)
212-
.execute()
213-
.await
214-
.expect("privileged user should get a 404 when trying to delete another user's token");
206+
object_delete_error(testctx, &token_url, StatusCode::NOT_FOUND).await;
215207

216208
// Test deleting the token as the owner
217209
NexusRequest::object_delete(testctx, &token_url)

nexus/tests/output/uncovered-authz-endpoints.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
API endpoints with no coverage in authz tests:
22
probe_delete (delete "/experimental/v1/probes/{probe}")
3-
current_user_token_delete (delete "/v1/me/device-tokens/{token_id}")
3+
current_user_device_token_delete (delete "/v1/me/device-tokens/{token_id}")
44
probe_list (get "/experimental/v1/probes")
55
probe_view (get "/experimental/v1/probes/{probe}")
66
support_bundle_download (get "/experimental/v1/system/support-bundles/{bundle_id}/download")

0 commit comments

Comments
 (0)