From 8b75265231724b0a71491032a117bd340b9b2da3 Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Fri, 30 May 2025 12:52:35 -0500 Subject: [PATCH] Migrate compute_ctl JWT scope claim to a vector Signed-off-by: Tristan Partin --- compute_tools/src/http/middleware/authorize.rs | 2 +- control_plane/src/bin/neon_local.rs | 4 ++-- control_plane/src/endpoint.rs | 12 +++++++----- libs/compute_api/src/requests.rs | 4 ++-- test_runner/fixtures/neon_cli.py | 8 +++----- test_runner/fixtures/neon_fixtures.py | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compute_tools/src/http/middleware/authorize.rs b/compute_tools/src/http/middleware/authorize.rs index a82f46e062..729b9f8e6b 100644 --- a/compute_tools/src/http/middleware/authorize.rs +++ b/compute_tools/src/http/middleware/authorize.rs @@ -71,7 +71,7 @@ impl AsyncAuthorizeRequest for Authorize { // Unauthorized because when we eventually do use // [`Validation`], we will hit the above `Err` match arm which // returns 401 Unauthorized. - Some(ComputeClaimsScope::Admin) => { + Some(ref scope) if scope.contains(&ComputeClaimsScope::Admin) => { let Some(ref audience) = data.claims.audience else { return Err(JsonResponse::error( StatusCode::UNAUTHORIZED, diff --git a/control_plane/src/bin/neon_local.rs b/control_plane/src/bin/neon_local.rs index ef6985d697..8abbdabf75 100644 --- a/control_plane/src/bin/neon_local.rs +++ b/control_plane/src/bin/neon_local.rs @@ -709,7 +709,7 @@ struct EndpointGenerateJwtCmdArgs { endpoint_id: String, #[clap(short = 's', long, help = "Scope to generate the JWT with", value_parser = ComputeClaimsScope::from_str)] - scope: Option, + scope: Vec, } #[derive(clap::Subcommand)] @@ -1580,7 +1580,7 @@ async fn handle_endpoint(subcmd: &EndpointCmd, env: &local_env::LocalEnv) -> Res .with_context(|| format!("postgres endpoint {endpoint_id} is not found"))? }; - let jwt = endpoint.generate_jwt(args.scope)?; + let jwt = endpoint.generate_jwt(Some(args.scope.clone()))?; print!("{jwt}"); } diff --git a/control_plane/src/endpoint.rs b/control_plane/src/endpoint.rs index 708745446d..280a308313 100644 --- a/control_plane/src/endpoint.rs +++ b/control_plane/src/endpoint.rs @@ -632,14 +632,16 @@ impl Endpoint { } /// Generate a JWT with the correct claims. - pub fn generate_jwt(&self, scope: Option) -> Result { + pub fn generate_jwt(&self, scope: Option>) -> Result { self.env.generate_auth_token(&ComputeClaims { audience: match scope { - Some(ComputeClaimsScope::Admin) => Some(vec![COMPUTE_AUDIENCE.to_owned()]), + Some(ref scope) if scope.contains(&ComputeClaimsScope::Admin) => { + Some(vec![COMPUTE_AUDIENCE.to_owned()]) + } _ => None, }, compute_id: match scope { - Some(ComputeClaimsScope::Admin) => None, + Some(ref scope) if scope.contains(&ComputeClaimsScope::Admin) => None, _ => Some(self.endpoint_id.clone()), }, scope, @@ -918,7 +920,7 @@ impl Endpoint { self.external_http_address.port() ), ) - .bearer_auth(self.generate_jwt(None::)?) + .bearer_auth(self.generate_jwt(None::>)?) .send() .await?; @@ -995,7 +997,7 @@ impl Endpoint { self.external_http_address.port() )) .header(CONTENT_TYPE.as_str(), "application/json") - .bearer_auth(self.generate_jwt(None::)?) + .bearer_auth(self.generate_jwt(None::>)?) .body( serde_json::to_string(&ConfigurationRequest { spec, diff --git a/libs/compute_api/src/requests.rs b/libs/compute_api/src/requests.rs index bbab271474..94b8d9e7bf 100644 --- a/libs/compute_api/src/requests.rs +++ b/libs/compute_api/src/requests.rs @@ -41,8 +41,8 @@ pub struct ComputeClaims { /// [`ComputeClaimsScope::Admin`]. pub compute_id: Option, - /// The scope of what the token authorizes. - pub scope: Option, + /// The scopes of what the token is authorized for. + pub scope: Option>, /// The recipient the token is intended for. /// diff --git a/test_runner/fixtures/neon_cli.py b/test_runner/fixtures/neon_cli.py index bb07e2b6d1..8a9d78916b 100644 --- a/test_runner/fixtures/neon_cli.py +++ b/test_runner/fixtures/neon_cli.py @@ -536,16 +536,14 @@ class NeonLocalCli(AbstractNeonCli): res.check_returncode() return res - def endpoint_generate_jwt( - self, endpoint_id: str, scope: ComputeClaimsScope | None = None - ) -> str: + def endpoint_generate_jwt(self, endpoint_id: str, scope: list[ComputeClaimsScope]) -> str: """ Generate a JWT for making requests to the endpoint's external HTTP server. """ args = ["endpoint", "generate-jwt", endpoint_id] - if scope: - args += ["--scope", str(scope)] + for s in scope: + args += ["--scope", str(s)] cmd = self.raw_cli(args) cmd.check_returncode() diff --git a/test_runner/fixtures/neon_fixtures.py b/test_runner/fixtures/neon_fixtures.py index ab4885ce6b..e518b0e6d2 100644 --- a/test_runner/fixtures/neon_fixtures.py +++ b/test_runner/fixtures/neon_fixtures.py @@ -4282,7 +4282,7 @@ class Endpoint(PgProtocol, LogUtils): self.config(config_lines) - self.__jwt = self.generate_jwt() + self.__jwt = self.generate_jwt([]) return self @@ -4329,7 +4329,7 @@ class Endpoint(PgProtocol, LogUtils): return self - def generate_jwt(self, scope: ComputeClaimsScope | None = None) -> str: + def generate_jwt(self, scope: list[ComputeClaimsScope]) -> str: """ Generate a JWT for making requests to the endpoint's external HTTP server.