Skip to content

Move /silos/ under /system/ as per RFD-288 #1728

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 21, 2022
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
4 changes: 2 additions & 2 deletions docs/debugging-authz.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ When Nexus decides that credentials weren't specified at all, one possible reaso
[source,text]
----
[2022-07-07T20:54:10.61484323Z] TRACE: ee3947d6-0adc-4e37-86ab-f49dcda0e886/dropshot_external/12898 on ivanova: authn: trying SchemeName("spoof") (req_id=a6febc45-7f95-4d79-86d5-93f7c2be4109, method=GET, remote_addr=127.0.0.1:36233, local_addr=127.0.0.1:63725)
uri: /silos/default-silo/saml_identity_providers/demo-saml-provider
uri: /system/silos/default-silo/saml_identity_providers/demo-saml-provider
[2022-07-07T20:54:10.615229923Z] TRACE: ee3947d6-0adc-4e37-86ab-f49dcda0e886/dropshot_external/12898 on ivanova: authn: trying SchemeName("session_cookie") (req_id=a6febc45-7f95-4d79-86d5-93f7c2be4109, method=GET, remote_addr=127.0.0.1:36233, local_addr=127.0.0.1:63725)
uri: /silos/default-silo/saml_identity_providers/demo-saml-provider
uri: /system/silos/default-silo/saml_identity_providers/demo-saml-provider
[2022-07-07T20:54:10.615630513Z] TRACE: ee3947d6-0adc-4e37-86ab-f49dcda0e886/dropshot_external/12898 on ivanova: authn result: Ok(Context { kind: Unauthenticated, schemes_tried: [SchemeName("spoof"), SchemeName("session_cookie")] }) (req_id=a6febc45-7f95-4d79-86d5-93f7c2be4109, method=GET, remote_addr=127.0.0.1:36233, local_addr=127.0.0.1:63725)
----

Expand Down
12 changes: 12 additions & 0 deletions nexus/src/app/silo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ impl super::Nexus {
Ok(db_silo)
}

pub async fn silo_fetch_by_id(
&self,
opctx: &OpContext,
silo_id: &Uuid,
) -> LookupResult<db::model::Silo> {
let (.., db_silo) = LookupPath::new(opctx, &self.db_datastore)
.silo_id(*silo_id)
.fetch()
.await?;
Ok(db_silo)
}

pub async fn silo_delete(
&self,
opctx: &OpContext,
Expand Down
2 changes: 1 addition & 1 deletion nexus/src/external_api/console_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ pub async fn spoof_login(
//
// TODO If the user does not have this information it's unclear what should
// happen. If they know the silo name they are trying to log into, they could
// `GET /silos/{silo_name}/identity_providers` in order to list available
// `GET /system/silos/{silo_name}/identity_providers` in order to list available
// identity providers. If not, TODO.
//
// Once the appropriate login URL is created, the user's browser is redirected:
Expand Down
59 changes: 41 additions & 18 deletions nexus/src/external_api/http_entrypoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ pub fn external_api() -> NexusApiDescription {
api.register(silo_list)?;
api.register(silo_create)?;
api.register(silo_view)?;
api.register(silo_view_by_id)?;
api.register(silo_delete)?;
api.register(silo_identity_provider_list)?;
api.register(silo_policy_view)?;
Expand Down Expand Up @@ -429,8 +430,8 @@ async fn policy_update(
/// Lists silos that are discoverable based on the current permissions.
#[endpoint {
method = GET,
path = "/silos",
tags = ["silos"],
path = "/system/silos",
tags = ["system"],
}]
async fn silo_list(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
Expand Down Expand Up @@ -472,8 +473,8 @@ async fn silo_list(
/// Create a silo
#[endpoint {
method = POST,
path = "/silos",
tags = ["silos"],
path = "/system/silos",
tags = ["system"],
}]
async fn silo_create(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
Expand Down Expand Up @@ -502,8 +503,8 @@ struct SiloPathParam {
/// Fetch a silo by name.
#[endpoint {
method = GET,
path = "/silos/{silo_name}",
tags = ["silos"],
path = "/system/silos/{silo_name}",
tags = ["system"],
}]
async fn silo_view(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
Expand All @@ -521,13 +522,35 @@ async fn silo_view(
apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await
}

/// Fetch a silo by id
#[endpoint {
method = GET,
path = "/system/by-id/silos/{id}",
tags = ["system"]
}]
async fn silo_view_by_id(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
path_params: Path<ByIdPathParams>,
) -> Result<HttpResponseOk<Silo>, HttpError> {
let apictx = rqctx.context();
let nexus = &apictx.nexus;
let path = path_params.into_inner();
let id = &path.id;
let handler = async {
let opctx = OpContext::for_external_api(&rqctx).await?;
let silo = nexus.silo_fetch_by_id(&opctx, id).await?;
Ok(HttpResponseOk(silo.into()))
};
apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await
}

/// Delete a silo
///
/// Delete a silo by name.
#[endpoint {
method = DELETE,
path = "/silos/{silo_name}",
tags = ["silos"],
path = "/system/silos/{silo_name}",
tags = ["system"],
}]
async fn silo_delete(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
Expand All @@ -548,8 +571,8 @@ async fn silo_delete(
/// Fetch a silo's IAM policy
#[endpoint {
method = GET,
path = "/silos/{silo_name}/policy",
tags = ["silos"],
path = "/system/silos/{silo_name}/policy",
tags = ["system"],
}]
async fn silo_policy_view(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
Expand All @@ -572,8 +595,8 @@ async fn silo_policy_view(
/// Update a silo's IAM policy
#[endpoint {
method = PUT,
path = "/silos/{silo_name}/policy",
tags = ["silos"],
path = "/system/silos/{silo_name}/policy",
tags = ["system"],
}]
async fn silo_policy_update(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
Expand Down Expand Up @@ -604,8 +627,8 @@ async fn silo_policy_update(
/// List a silo's IDPs
#[endpoint {
method = GET,
path = "/silos/{silo_name}/identity-providers",
tags = ["silos"],
path = "/system/silos/{silo_name}/identity-providers",
tags = ["system"],
}]
async fn silo_identity_provider_list(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
Expand Down Expand Up @@ -641,8 +664,8 @@ async fn silo_identity_provider_list(
/// Create a SAML IDP
#[endpoint {
method = POST,
path = "/silos/{silo_name}/saml-identity-providers",
tags = ["silos"],
path = "/system/silos/{silo_name}/saml-identity-providers",
tags = ["system"],
}]
async fn silo_identity_provider_create(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
Expand Down Expand Up @@ -678,8 +701,8 @@ struct SiloSamlPathParam {
/// Fetch a SAML IDP
#[endpoint {
method = GET,
path = "/silos/{silo_name}/saml-identity-providers/{provider_name}",
tags = ["silos"],
path = "/system/silos/{silo_name}/saml-identity-providers/{provider_name}",
tags = ["system"],
}]
async fn silo_identity_provider_view(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
Expand Down
2 changes: 1 addition & 1 deletion nexus/test-utils/src/resource_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub async fn create_silo(
) -> Silo {
object_create(
client,
"/silos",
"/system/silos",
&params::SiloCreate {
identity: IdentityMetadataCreateParams {
name: silo_name.parse().unwrap(),
Expand Down
34 changes: 19 additions & 15 deletions nexus/tests/integration_tests/authz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,13 +260,16 @@ async fn test_list_silo_idps_for_unpriv(cptestctx: &ControlPlaneTestContext) {
.unwrap();

let _users: ResultsPage<views::IdentityProvider> =
NexusRequest::object_get(client, &"/silos/authz/identity-providers")
.authn_as(AuthnMode::SiloUser(new_silo_user_id))
.execute()
.await
.expect("failed to make GET request")
.parsed_body()
.unwrap();
NexusRequest::object_get(
client,
&"/system/silos/authz/identity-providers",
)
.authn_as(AuthnMode::SiloUser(new_silo_user_id))
.execute()
.await
.expect("failed to make GET request")
.parsed_body()
.unwrap();
}

// Test that an authenticated, unprivileged user can access /session/me
Expand Down Expand Up @@ -319,17 +322,18 @@ async fn test_silo_read_for_unpriv(cptestctx: &ControlPlaneTestContext) {
.await;

// That user can access their own silo
let _silo: views::Silo = NexusRequest::object_get(client, &"/silos/authz")
.authn_as(AuthnMode::SiloUser(new_silo_user_id))
.execute()
.await
.expect("failed to make GET request")
.parsed_body()
.unwrap();
let _silo: views::Silo =
NexusRequest::object_get(client, &"/system/silos/authz")
.authn_as(AuthnMode::SiloUser(new_silo_user_id))
.execute()
.await
.expect("failed to make GET request")
.parsed_body()
.unwrap();

// But not others
NexusRequest::new(
RequestBuilder::new(client, http::Method::GET, &"/silos/other")
RequestBuilder::new(client, http::Method::GET, &"/system/silos/other")
.expect_status(Some(http::StatusCode::NOT_FOUND)),
)
.authn_as(AuthnMode::SiloUser(new_silo_user_id))
Expand Down
2 changes: 1 addition & 1 deletion nexus/tests/integration_tests/console_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ async fn test_sessions(cptestctx: &ControlPlaneTestContext) {
// without other privileges. However, they _do_ need the privilege to
// create Organizations because we'll be testing that as a smoke test.
// We'll remove that privilege afterwards.
let silo_url = format!("/silos/{}", DEFAULT_SILO.identity().name);
let silo_url = format!("/system/silos/{}", DEFAULT_SILO.identity().name);
let policy_url = format!("{}/policy", silo_url);
let initial_policy: shared::Policy<SiloRole> =
NexusRequest::object_get(testctx, &policy_url)
Expand Down
18 changes: 13 additions & 5 deletions nexus/tests/integration_tests/endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ lazy_static! {
// Silo used for testing
pub static ref DEMO_SILO_NAME: Name = "demo-silo".parse().unwrap();
pub static ref DEMO_SILO_URL: String =
format!("/silos/{}", *DEMO_SILO_NAME);
format!("/system/silos/{}", *DEMO_SILO_NAME);
pub static ref DEMO_SILO_POLICY_URL: String =
format!("/silos/{}/policy", *DEMO_SILO_NAME);
format!("/system/silos/{}/policy", *DEMO_SILO_NAME);
pub static ref DEMO_SILO_CREATE: params::SiloCreate =
params::SiloCreate {
identity: IdentityMetadataCreateParams {
Expand Down Expand Up @@ -360,8 +360,8 @@ lazy_static! {

lazy_static! {
// Identity providers
pub static ref IDENTITY_PROVIDERS_URL: String = format!("/silos/default-silo/identity-providers");
pub static ref SAML_IDENTITY_PROVIDERS_URL: String = format!("/silos/default-silo/saml-identity-providers");
pub static ref IDENTITY_PROVIDERS_URL: String = format!("/system/silos/default-silo/identity-providers");
pub static ref SAML_IDENTITY_PROVIDERS_URL: String = format!("/system/silos/default-silo/saml-identity-providers");

pub static ref DEMO_SAML_IDENTITY_PROVIDER_NAME: Name = "demo-saml-provider".parse().unwrap();
pub static ref SPECIFIC_SAML_IDENTITY_PROVIDER_URL: String = format!("{}/{}", *SAML_IDENTITY_PROVIDERS_URL, *DEMO_SAML_IDENTITY_PROVIDER_NAME);
Expand Down Expand Up @@ -648,7 +648,7 @@ lazy_static! {

/* Silos */
VerifyEndpoint {
url: "/silos",
url: "/system/silos",
visibility: Visibility::Public,
unprivileged_access: UnprivilegedAccess::None,
allowed_methods: vec![
Expand All @@ -658,6 +658,14 @@ lazy_static! {
)
],
},
VerifyEndpoint {
url: "/system/by-id/silos/{id}",
visibility: Visibility::Protected,
unprivileged_access: UnprivilegedAccess::None,
allowed_methods: vec![
AllowedMethod::Get,
],
},
VerifyEndpoint {
url: &*DEMO_SILO_URL,
visibility: Visibility::Protected,
Expand Down
2 changes: 1 addition & 1 deletion nexus/tests/integration_tests/role_assignments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ async fn test_role_assignments_silo(cptestctx: &ControlPlaneTestContext) {
const VISIBLE_TO_UNPRIVILEGED: bool = true;
fn policy_url(&self) -> String {
format!(
"/silos/{}/policy",
"/system/silos/{}/policy",
fixed_data::silo::DEFAULT_SILO.identity().name.to_string()
)
}
Expand Down
Loading