Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion nexus/src/external_api/http_entrypoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7149,10 +7149,31 @@ impl NexusExternalApi for NexusExternalApiImpl {
let opctx =
crate::context::op_context_for_external_api(&rqctx).await?;
let user = nexus.silo_user_fetch_self(&opctx).await?;
let (_, silo) = nexus.current_silo_lookup(&opctx)?.fetch().await?;
let (authz_silo, silo) =
nexus.current_silo_lookup(&opctx)?.fetch().await?;

// only eat Forbidden errors indicating lack of perms. other errors
// blow up normally
let fleet_viewer =
match opctx.authorize(authz::Action::Read, &authz::FLEET).await
{
Ok(()) => true,
Err(Error::Forbidden) => false,
Err(e) => return Err(e.into()),
};
let silo_admin =
match opctx.authorize(authz::Action::Modify, &authz_silo).await
{
Ok(()) => true,
Err(Error::Forbidden) => false,
Err(e) => return Err(e.into()),
};

Ok(HttpResponseOk(views::CurrentUser {
user: user.into(),
silo_name: silo.name().clone(),
fleet_viewer,
silo_admin,
}))
};
apictx
Expand Down
46 changes: 43 additions & 3 deletions nexus/tests/integration_tests/console_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ use nexus_test_utils::resource_helpers::{
use nexus_test_utils::{load_test_config, test_setup_with_config};
use nexus_test_utils_macros::nexus_test;
use nexus_types::external_api::params::{self, ProjectCreate};
use nexus_types::external_api::shared::{SiloIdentityMode, SiloRole};
use nexus_types::external_api::shared::{
FleetRole, SiloIdentityMode, SiloRole,
};
use nexus_types::external_api::{shared, views};
use omicron_common::api::external::{Error, IdentityMetadataCreateParams};
use omicron_sled_agent::sim;
Expand Down Expand Up @@ -437,7 +439,9 @@ async fn test_session_me(cptestctx: &ControlPlaneTestContext) {
display_name: USER_TEST_PRIVILEGED.external_id.clone(),
silo_id: DEFAULT_SILO.id(),
},
silo_name: DEFAULT_SILO.name().clone()
silo_name: DEFAULT_SILO.name().clone(),
fleet_viewer: true,
silo_admin: true,
}
);

Expand All @@ -454,9 +458,45 @@ async fn test_session_me(cptestctx: &ControlPlaneTestContext) {
display_name: USER_TEST_UNPRIVILEGED.external_id.clone(),
silo_id: DEFAULT_SILO.id(),
},
silo_name: DEFAULT_SILO.name().clone()
silo_name: DEFAULT_SILO.name().clone(),
fleet_viewer: false,
silo_admin: false,
}
);

// now make unpriv user silo admin and see it change
grant_iam(
testctx,
&format!("/v1/system/silos/{}", DEFAULT_SILO.identity().name),
SiloRole::Admin,
USER_TEST_UNPRIVILEGED.id(),
AuthnMode::PrivilegedUser,
)
.await;

let unpriv_user = NexusRequest::object_get(testctx, "/v1/me")
.authn_as(AuthnMode::UnprivilegedUser)
.execute_and_parse_unwrap::<views::CurrentUser>()
.await;
assert!(!unpriv_user.fleet_viewer);
assert!(unpriv_user.silo_admin);

// now grant fleet viewer and see that one change
grant_iam(
testctx,
"/v1/system",
FleetRole::Admin,
USER_TEST_UNPRIVILEGED.id(),
AuthnMode::PrivilegedUser,
)
.await;

let unpriv_user = NexusRequest::object_get(testctx, "/v1/me")
.authn_as(AuthnMode::UnprivilegedUser)
.execute_and_parse_unwrap::<views::CurrentUser>()
.await;
assert!(unpriv_user.fleet_viewer);
assert!(unpriv_user.silo_admin);
}

#[nexus_test]
Expand Down
11 changes: 10 additions & 1 deletion nexus/types/src/external_api/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -955,9 +955,18 @@ pub struct User {
pub struct CurrentUser {
#[serde(flatten)]
pub user: User,

/** Name of the silo to which this user belongs. */
pub silo_name: Name,
/**
* Whether this user has the viewer role on the fleet. Used by the web
* console to determine whether to show system-level UI.
*/
pub fleet_viewer: bool,
/**
* Whether this user has the admin role on their silo. Used by the web
* console to determine whether to show admin-only UI elements.
*/
pub silo_admin: bool,
}

// SILO GROUPS
Expand Down
10 changes: 10 additions & 0 deletions openapi/nexus.json
Original file line number Diff line number Diff line change
Expand Up @@ -16819,10 +16819,18 @@
"description": "Human-readable name that can identify the user",
"type": "string"
},
"fleet_viewer": {
"description": "Whether this user has the viewer role on the fleet. Used by the web console to determine whether to show system-level UI.",
"type": "boolean"
},
"id": {
"type": "string",
"format": "uuid"
},
"silo_admin": {
"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.",
"type": "boolean"
},
"silo_id": {
"description": "Uuid of the silo to which this user belongs",
"type": "string",
Expand All @@ -16839,7 +16847,9 @@
},
"required": [
"display_name",
"fleet_viewer",
"id",
"silo_admin",
"silo_id",
"silo_name"
]
Expand Down
Loading