Skip to content

Commit 3e15398

Browse files
committed
implicit authz on token list and delete by using current actor ID
1 parent 740ecd2 commit 3e15398

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};
@@ -297,34 +297,14 @@ impl super::Nexus {
297297
opctx: &OpContext,
298298
pagparams: &DataPageParams<'_, Uuid>,
299299
) -> ListResultVec<DeviceAccessToken> {
300-
let &actor = opctx
301-
.authn
302-
.actor_required()
303-
.internal_context("loading current user to list tokens")?;
304-
let (.., authz_user) = LookupPath::new(opctx, self.datastore())
305-
.silo_user_id(actor.actor_id())
306-
.lookup_for(authz::Action::ListChildren)
307-
.await?;
308-
self.db_datastore
309-
.device_access_tokens_list(opctx, &authz_user, pagparams)
310-
.await
300+
self.db_datastore.current_user_token_list(opctx, pagparams).await
311301
}
312302

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

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)