diff --git a/packages/api/actor/src/auth.rs b/packages/api/actor/src/auth.rs index bbf6502e70..506f319ffc 100644 --- a/packages/api/actor/src/auth.rs +++ b/packages/api/actor/src/auth.rs @@ -12,6 +12,12 @@ pub struct Auth { claims: Option, } +pub struct CheckOpts<'a> { + pub query: &'a GlobalQuery, + pub allow_service_token: bool, + pub opt_auth: bool, +} + pub struct CheckOutput { pub game_id: Uuid, pub env_id: Uuid, @@ -65,13 +71,12 @@ impl Auth { pub async fn check( &self, ctx: &OperationContext<()>, - query: &GlobalQuery, - allow_service: bool, + opts: CheckOpts<'_>, ) -> GlobalResult { let is_development = ctx.config().server()?.rivet.auth.access_kind == rivet_config::config::rivet::AccessKind::Development; - let (project_query, environment_query) = query.project_and_env()?; + let (project_query, environment_query) = opts.query.project_and_env()?; // Lookup project name ID let project = if is_development { @@ -121,6 +126,11 @@ impl Auth { return Ok(output); } + // Skip auth if not needed + if self.claims.is_none() && opts.opt_auth { + return Ok(output); + } + // Validate claims let claims = self.claims()?; @@ -134,7 +144,7 @@ impl Auth { Ok(output) } else if let Ok(service_ent) = claims.as_env_service() { ensure_with!( - allow_service, + opts.allow_service_token, API_FORBIDDEN, reason = "Cannot use service token for this endpoint." ); diff --git a/packages/api/actor/src/route/actors.rs b/packages/api/actor/src/route/actors.rs index b8f7cd83cb..7526cc383c 100644 --- a/packages/api/actor/src/route/actors.rs +++ b/packages/api/actor/src/route/actors.rs @@ -11,7 +11,7 @@ use serde_json::json; use crate::{ assert, - auth::{Auth, CheckOutput}, + auth::{Auth, CheckOpts, CheckOutput}, utils::build_global_query_compat, }; @@ -40,7 +40,17 @@ async fn get_inner( _watch_index: WatchIndexQuery, query: GlobalEndpointTypeQuery, ) -> GlobalResult { - let CheckOutput { env_id, .. } = ctx.auth().check(ctx.op_ctx(), &query.global, true).await?; + let CheckOutput { env_id, .. } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query.global, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; // Get the server let servers_res = ctx @@ -119,8 +129,17 @@ pub async fn create( body: models::ActorCreateActorRequest, query: GlobalEndpointTypeQuery, ) -> GlobalResult { - let CheckOutput { game_id, env_id } = - ctx.auth().check(ctx.op_ctx(), &query.global, true).await?; + let CheckOutput { game_id, env_id } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query.global, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; let (clusters_res, game_configs_res, build) = tokio::try_join!( ctx.op(cluster::ops::get_for_game::Input { @@ -408,8 +427,17 @@ pub async fn destroy( actor_id: Uuid, query: DeleteQuery, ) -> GlobalResult { - let CheckOutput { game_id, env_id } = - ctx.auth().check(ctx.op_ctx(), &query.global, true).await?; + let CheckOutput { game_id, env_id } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query.global, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; ensure_with!( query.override_kill_timeout.unwrap_or(0) >= 0, @@ -474,7 +502,17 @@ pub async fn upgrade( body: models::ActorUpgradeActorRequest, query: GlobalQuery, ) -> GlobalResult { - let CheckOutput { game_id, env_id } = ctx.auth().check(ctx.op_ctx(), &query, false).await?; + let CheckOutput { game_id, env_id } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; assert::server_for_env(&ctx, actor_id, game_id, env_id, None).await?; @@ -502,7 +540,17 @@ pub async fn upgrade_all( body: models::ActorUpgradeAllActorsRequest, query: GlobalQuery, ) -> GlobalResult { - let CheckOutput { game_id, env_id } = ctx.auth().check(ctx.op_ctx(), &query, false).await?; + let CheckOutput { game_id, env_id } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; let tags = unwrap_with!(body.tags, API_BAD_BODY, error = "missing property `tags`"); @@ -622,9 +670,16 @@ async fn list_actors_inner( _watch_index: WatchIndexQuery, query: ListQuery, ) -> GlobalResult { - let CheckOutput { env_id, .. } = ctx + let CheckOutput { game_id, env_id } = ctx .auth() - .check(ctx.op_ctx(), &query.global_endpoint_type.global, true) + .check( + ctx.op_ctx(), + CheckOpts { + query: &query.global_endpoint_type.global, + allow_service_token: true, + opt_auth: false, + }, + ) .await?; let include_destroyed = query.include_destroyed.unwrap_or(false); diff --git a/packages/api/actor/src/route/builds.rs b/packages/api/actor/src/route/builds.rs index c7f9574190..0e73f82e00 100644 --- a/packages/api/actor/src/route/builds.rs +++ b/packages/api/actor/src/route/builds.rs @@ -9,7 +9,7 @@ use serde_json::json; use util::timestamp; use crate::{ - auth::{Auth, CheckOutput}, + auth::{Auth, CheckOpts, CheckOutput}, utils::build_global_query_compat, }; @@ -22,7 +22,17 @@ pub async fn get( _watch_index: WatchIndexQuery, query: GlobalQuery, ) -> GlobalResult { - let CheckOutput { env_id, .. } = ctx.auth().check(ctx.op_ctx(), &query, true).await?; + let CheckOutput { env_id, .. } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; let builds_res = op!([ctx] build_get { build_ids: vec![build_id.into()], @@ -87,7 +97,17 @@ pub async fn list( _watch_index: WatchIndexQuery, query: ListQuery, ) -> GlobalResult { - let CheckOutput { env_id, .. } = ctx.auth().check(ctx.op_ctx(), &query.global, true).await?; + let CheckOutput { env_id, .. } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query.global, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; let list_res = op!([ctx] build_list_for_env { env_id: Some(env_id.into()), @@ -183,7 +203,17 @@ pub async fn patch_tags( body: models::ActorPatchBuildTagsRequest, query: GlobalQuery, ) -> GlobalResult { - let CheckOutput { env_id, .. } = ctx.auth().check(ctx.op_ctx(), &query, true).await?; + let CheckOutput { env_id, .. } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; let tags = unwrap_with!(body.tags, API_BAD_BODY, error = "missing field `tags`"); @@ -268,7 +298,17 @@ pub async fn create_build( body: models::ActorPrepareBuildRequest, query: GlobalQuery, ) -> GlobalResult { - let CheckOutput { env_id, .. } = ctx.auth().check(ctx.op_ctx(), &query, true).await?; + let CheckOutput { env_id, .. } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; let (kind, image_tag) = match body.kind { Option::None | Some(models::ActorBuildKind::DockerImage) => ( @@ -372,7 +412,17 @@ pub async fn complete_build( _body: serde_json::Value, query: GlobalQuery, ) -> GlobalResult { - let CheckOutput { env_id, .. } = ctx.auth().check(ctx.op_ctx(), &query, true).await?; + let CheckOutput { env_id, .. } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query, + allow_service_token: true, + opt_auth: false, + }, + ) + .await?; let build_res = op!([ctx] build_get { build_ids: vec![build_id.into()], diff --git a/packages/api/actor/src/route/logs.rs b/packages/api/actor/src/route/logs.rs index feb413526f..d76b4f2e8a 100644 --- a/packages/api/actor/src/route/logs.rs +++ b/packages/api/actor/src/route/logs.rs @@ -10,7 +10,7 @@ use std::time::Duration; use crate::{ assert, - auth::{Auth, CheckOutput}, + auth::{Auth, CheckOpts, CheckOutput}, utils::build_global_query_compat, }; @@ -30,8 +30,17 @@ pub async fn get_logs( watch_index: WatchIndexQuery, query: GetActorLogsQuery, ) -> GlobalResult { - let CheckOutput { game_id, env_id } = - ctx.auth().check(ctx.op_ctx(), &query.global, false).await?; + let CheckOutput { game_id, env_id } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query.global, + allow_service_token: false, + opt_auth: false, + }, + ) + .await?; // Validate server belongs to game assert::server_for_env(&ctx, server_id, game_id, env_id, None).await?; diff --git a/packages/api/actor/src/route/regions.rs b/packages/api/actor/src/route/regions.rs index 0e53d50437..31841e9b95 100644 --- a/packages/api/actor/src/route/regions.rs +++ b/packages/api/actor/src/route/regions.rs @@ -5,7 +5,7 @@ use rivet_operation::prelude::*; use serde::Deserialize; use crate::{ - auth::{Auth, CheckOutput}, + auth::{Auth, CheckOpts, CheckOutput}, utils::build_global_query_compat, }; @@ -17,7 +17,17 @@ pub async fn list( _watch_index: WatchIndexQuery, query: GlobalQuery, ) -> GlobalResult { - let CheckOutput { game_id, .. } = ctx.auth().check(ctx.op_ctx(), &query, true).await?; + let CheckOutput { game_id, .. } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query, + allow_service_token: true, + opt_auth: true, + }, + ) + .await?; let cluster_res = ctx .op(cluster::ops::get_for_game::Input { @@ -61,7 +71,17 @@ pub async fn list_deprecated( _watch_index: WatchIndexQuery, ) -> GlobalResult { let query = build_global_query_compat(&ctx, game_id, env_id).await?; - let CheckOutput { game_id, .. } = ctx.auth().check(ctx.op_ctx(), &query, true).await?; + let CheckOutput { game_id, .. } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query, + allow_service_token: true, + opt_auth: true, + }, + ) + .await?; let cluster_res = ctx .op(cluster::ops::get_for_game::Input { @@ -113,7 +133,17 @@ pub async fn resolve( _watch_index: WatchIndexQuery, query: ResolveQuery, ) -> GlobalResult { - let CheckOutput { game_id, .. } = ctx.auth().check(ctx.op_ctx(), &query.global, true).await?; + let CheckOutput { game_id, .. } = ctx + .auth() + .check( + ctx.op_ctx(), + CheckOpts { + query: &query.global, + allow_service_token: true, + opt_auth: true, + }, + ) + .await?; // Resolve coords let coords = match (query.lat, query.long) {