Skip to content

Commit c52ed36

Browse files
authored
Add boolean fleet_viewer and silo_admin to /v1/me response (#8861)
Dramatically simpler alternative to #8515. Rather than doing the rigmarole required to get the actual specific role on the fleet and silo, we just do little authz checks to get the specific things we care about. The web console is the only consumer that cares about this endpoint so it feels fine to do it that way.
1 parent 07ef231 commit c52ed36

File tree

4 files changed

+85
-5
lines changed

4 files changed

+85
-5
lines changed

nexus/src/external_api/http_entrypoints.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7149,10 +7149,31 @@ impl NexusExternalApi for NexusExternalApiImpl {
71497149
let opctx =
71507150
crate::context::op_context_for_external_api(&rqctx).await?;
71517151
let user = nexus.silo_user_fetch_self(&opctx).await?;
7152-
let (_, silo) = nexus.current_silo_lookup(&opctx)?.fetch().await?;
7152+
let (authz_silo, silo) =
7153+
nexus.current_silo_lookup(&opctx)?.fetch().await?;
7154+
7155+
// only eat Forbidden errors indicating lack of perms. other errors
7156+
// blow up normally
7157+
let fleet_viewer =
7158+
match opctx.authorize(authz::Action::Read, &authz::FLEET).await
7159+
{
7160+
Ok(()) => true,
7161+
Err(Error::Forbidden) => false,
7162+
Err(e) => return Err(e.into()),
7163+
};
7164+
let silo_admin =
7165+
match opctx.authorize(authz::Action::Modify, &authz_silo).await
7166+
{
7167+
Ok(()) => true,
7168+
Err(Error::Forbidden) => false,
7169+
Err(e) => return Err(e.into()),
7170+
};
7171+
71537172
Ok(HttpResponseOk(views::CurrentUser {
71547173
user: user.into(),
71557174
silo_name: silo.name().clone(),
7175+
fleet_viewer,
7176+
silo_admin,
71567177
}))
71577178
};
71587179
apictx

nexus/tests/integration_tests/console_api.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ use nexus_test_utils::resource_helpers::{
2424
use nexus_test_utils::{load_test_config, test_setup_with_config};
2525
use nexus_test_utils_macros::nexus_test;
2626
use nexus_types::external_api::params::{self, ProjectCreate};
27-
use nexus_types::external_api::shared::{SiloIdentityMode, SiloRole};
27+
use nexus_types::external_api::shared::{
28+
FleetRole, SiloIdentityMode, SiloRole,
29+
};
2830
use nexus_types::external_api::{shared, views};
2931
use omicron_common::api::external::{Error, IdentityMetadataCreateParams};
3032
use omicron_sled_agent::sim;
@@ -437,7 +439,9 @@ async fn test_session_me(cptestctx: &ControlPlaneTestContext) {
437439
display_name: USER_TEST_PRIVILEGED.external_id.clone(),
438440
silo_id: DEFAULT_SILO.id(),
439441
},
440-
silo_name: DEFAULT_SILO.name().clone()
442+
silo_name: DEFAULT_SILO.name().clone(),
443+
fleet_viewer: true,
444+
silo_admin: true,
441445
}
442446
);
443447

@@ -454,9 +458,45 @@ async fn test_session_me(cptestctx: &ControlPlaneTestContext) {
454458
display_name: USER_TEST_UNPRIVILEGED.external_id.clone(),
455459
silo_id: DEFAULT_SILO.id(),
456460
},
457-
silo_name: DEFAULT_SILO.name().clone()
461+
silo_name: DEFAULT_SILO.name().clone(),
462+
fleet_viewer: false,
463+
silo_admin: false,
458464
}
459465
);
466+
467+
// now make unpriv user silo admin and see it change
468+
grant_iam(
469+
testctx,
470+
&format!("/v1/system/silos/{}", DEFAULT_SILO.identity().name),
471+
SiloRole::Admin,
472+
USER_TEST_UNPRIVILEGED.id(),
473+
AuthnMode::PrivilegedUser,
474+
)
475+
.await;
476+
477+
let unpriv_user = NexusRequest::object_get(testctx, "/v1/me")
478+
.authn_as(AuthnMode::UnprivilegedUser)
479+
.execute_and_parse_unwrap::<views::CurrentUser>()
480+
.await;
481+
assert!(!unpriv_user.fleet_viewer);
482+
assert!(unpriv_user.silo_admin);
483+
484+
// now grant fleet viewer and see that one change
485+
grant_iam(
486+
testctx,
487+
"/v1/system",
488+
FleetRole::Admin,
489+
USER_TEST_UNPRIVILEGED.id(),
490+
AuthnMode::PrivilegedUser,
491+
)
492+
.await;
493+
494+
let unpriv_user = NexusRequest::object_get(testctx, "/v1/me")
495+
.authn_as(AuthnMode::UnprivilegedUser)
496+
.execute_and_parse_unwrap::<views::CurrentUser>()
497+
.await;
498+
assert!(unpriv_user.fleet_viewer);
499+
assert!(unpriv_user.silo_admin);
460500
}
461501

462502
#[nexus_test]

nexus/types/src/external_api/views.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,9 +955,18 @@ pub struct User {
955955
pub struct CurrentUser {
956956
#[serde(flatten)]
957957
pub user: User,
958-
959958
/** Name of the silo to which this user belongs. */
960959
pub silo_name: Name,
960+
/**
961+
* Whether this user has the viewer role on the fleet. Used by the web
962+
* console to determine whether to show system-level UI.
963+
*/
964+
pub fleet_viewer: bool,
965+
/**
966+
* Whether this user has the admin role on their silo. Used by the web
967+
* console to determine whether to show admin-only UI elements.
968+
*/
969+
pub silo_admin: bool,
961970
}
962971

963972
// SILO GROUPS

openapi/nexus.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16819,10 +16819,18 @@
1681916819
"description": "Human-readable name that can identify the user",
1682016820
"type": "string"
1682116821
},
16822+
"fleet_viewer": {
16823+
"description": "Whether this user has the viewer role on the fleet. Used by the web console to determine whether to show system-level UI.",
16824+
"type": "boolean"
16825+
},
1682216826
"id": {
1682316827
"type": "string",
1682416828
"format": "uuid"
1682516829
},
16830+
"silo_admin": {
16831+
"description": "Whether this user has the admin role on their silo. Used by the web console to determine whether to show admin-only UI elements.",
16832+
"type": "boolean"
16833+
},
1682616834
"silo_id": {
1682716835
"description": "Uuid of the silo to which this user belongs",
1682816836
"type": "string",
@@ -16839,7 +16847,9 @@
1683916847
},
1684016848
"required": [
1684116849
"display_name",
16850+
"fleet_viewer",
1684216851
"id",
16852+
"silo_admin",
1684316853
"silo_id",
1684416854
"silo_name"
1684516855
]

0 commit comments

Comments
 (0)