Skip to content

Commit 2a835d3

Browse files
committed
disallow 0 max ttl
1 parent a14c0dc commit 2a835d3

File tree

6 files changed

+33
-11
lines changed

6 files changed

+33
-11
lines changed

nexus/db-model/src/silo_settings.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ pub struct SiloSettingsUpdate {
5757
impl From<params::SiloSettingsUpdate> for SiloSettingsUpdate {
5858
fn from(params: params::SiloSettingsUpdate) -> Self {
5959
Self {
60-
device_token_max_ttl_seconds: params.device_token_max_ttl_seconds,
60+
device_token_max_ttl_seconds: params
61+
.device_token_max_ttl_seconds
62+
.map(|ttl| ttl.get().into()),
6163
time_modified: Utc::now(),
6264
}
6365
}

nexus/tests/integration_tests/device_auth.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5+
use std::num::NonZeroU32;
6+
57
use dropshot::test_util::ClientTestContext;
68
use nexus_auth::authn::USER_TEST_UNPRIVILEGED;
79
use nexus_db_queries::db::fixed_data::silo::DEFAULT_SILO;
810
use nexus_db_queries::db::identity::{Asset, Resource};
911
use nexus_test_utils::http_testing::TestResponse;
10-
use nexus_test_utils::resource_helpers::{object_get, object_put};
12+
use nexus_test_utils::resource_helpers::{
13+
object_get, object_put, object_put_error,
14+
};
1115
use nexus_test_utils::{
1216
http_testing::{AuthnMode, NexusRequest, RequestBuilder},
1317
resource_helpers::grant_iam,
@@ -245,9 +249,8 @@ async fn get_device_token(testctx: &ClientTestContext) -> String {
245249
token.access_token
246250
}
247251

248-
/// similar to the above except happy path only, focused on expiration
249252
#[nexus_test]
250-
async fn test_device_auth_expiration(cptestctx: &ControlPlaneTestContext) {
253+
async fn test_device_token_expiration(cptestctx: &ControlPlaneTestContext) {
251254
let testctx = &cptestctx.external_client;
252255

253256
let settings: views::SiloSettings =
@@ -263,11 +266,26 @@ async fn test_device_auth_expiration(cptestctx: &ControlPlaneTestContext) {
263266
.await
264267
.expect("initial token should work");
265268

269+
// passing negative or zero gives a 400
270+
for value in [-3, 0] {
271+
let error = object_put_error(
272+
testctx,
273+
"/v1/settings",
274+
&serde_json::json!({ "device_token_max_ttl_seconds": value }),
275+
StatusCode::BAD_REQUEST,
276+
)
277+
.await;
278+
let msg = "unable to parse JSON body: device_token_max_ttl_seconds: invalid value";
279+
assert!(error.message.starts_with(&msg));
280+
}
281+
266282
// set token expiration on silo to 3 seconds
267283
let settings: views::SiloSettings = object_put(
268284
testctx,
269285
"/v1/settings",
270-
&params::SiloSettingsUpdate { device_token_max_ttl_seconds: Some(3) },
286+
&params::SiloSettingsUpdate {
287+
device_token_max_ttl_seconds: NonZeroU32::new(3),
288+
},
271289
)
272290
.await;
273291

nexus/types/src/external_api/params.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use serde::{
2828
use std::collections::BTreeMap;
2929
use std::collections::BTreeSet;
3030
use std::collections::HashMap;
31+
use std::num::NonZeroU32;
3132
use std::{net::IpAddr, str::FromStr};
3233
use url::Url;
3334
use uuid::Uuid;
@@ -490,12 +491,12 @@ pub struct SiloQuotasUpdate {
490491
// was discussed.
491492

492493
/// Updateable properties of a silo's settings.
493-
/// If a value is omitted it will not be updated.
494494
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
495495
pub struct SiloSettingsUpdate {
496496
/// Maximum lifetime of a device token in seconds. If unset (or set to
497497
/// null), users will be able to create tokens that do not expire.
498-
pub device_token_max_ttl_seconds: Option<i64>,
498+
#[schemars(range(min = 1))]
499+
pub device_token_max_ttl_seconds: Option<NonZeroU32>,
499500
}
500501

501502
/// Create-time parameters for a `User`

openapi/nexus.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22889,14 +22889,15 @@
2288922889
]
2289022890
},
2289122891
"SiloSettingsUpdate": {
22892-
"description": "Updateable properties of a silo's settings. If a value is omitted it will not be updated.",
22892+
"description": "Updateable properties of a silo's settings.",
2289322893
"type": "object",
2289422894
"properties": {
2289522895
"device_token_max_ttl_seconds": {
2289622896
"nullable": true,
2289722897
"description": "Maximum lifetime of a device token in seconds. If unset (or set to null), users will be able to create tokens that do not expire.",
2289822898
"type": "integer",
22899-
"format": "int64"
22899+
"format": "uint32",
22900+
"minimum": 1
2290022901
}
2290122902
}
2290222903
},

schema/crdb/dbinit.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@ CREATE TABLE IF NOT EXISTS omicron.public.silo_settings (
10711071
time_modified TIMESTAMPTZ NOT NULL,
10721072

10731073
-- null means no max: users can tokens that never expire
1074-
device_token_max_ttl_seconds INT8
1074+
device_token_max_ttl_seconds INT8 CHECK (device_token_max_ttl_seconds > 0)
10751075
);
10761076
/*
10771077
* Projects

schema/crdb/silo-settings-token-expiration/up01.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ CREATE TABLE IF NOT EXISTS omicron.public.silo_settings (
44
time_modified TIMESTAMPTZ NOT NULL,
55

66
-- null means no max: users can tokens that never expire
7-
device_token_max_ttl_seconds INT8
7+
device_token_max_ttl_seconds INT8 CHECK (device_token_max_ttl_seconds > 0)
88
);

0 commit comments

Comments
 (0)