Skip to content

Commit

Permalink
fix: inaccessible admin routes (#555)
Browse files Browse the repository at this point in the history
<!-- Please make sure there is an issue that this PR is correlated to. -->

## Changes

<!-- If there are frontend changes, please include screenshots. -->
  • Loading branch information
NathanFlurry committed Mar 1, 2024
1 parent 3780eaa commit 9896b09
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 48 deletions.
32 changes: 14 additions & 18 deletions svc/api/cloud/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use api_helper::{
auth::{ApiAuth, AuthRateLimitCtx},
util::{as_auth_expired, basic_rate_limit},
};
use proto::claims::Claims;
use proto::{backend, claims::Claims};
use rivet_claims::ClaimsDecode;
use rivet_operation::prelude::*;

Expand Down Expand Up @@ -44,7 +44,10 @@ impl Auth {
.ok_or_else(|| err_code!(API_UNAUTHORIZED, reason = "No bearer token provided."))
}

pub async fn user(&self, ctx: &OperationContext<()>) -> GlobalResult<rivet_claims::ent::User> {
pub async fn user(
&self,
ctx: &OperationContext<()>,
) -> GlobalResult<(backend::user::User, rivet_claims::ent::User)> {
let claims = self.claims()?;
let user_ent = claims.as_user()?;

Expand All @@ -65,7 +68,7 @@ impl Auth {
bail_with!(TOKEN_REVOKED);
}

Ok(user_ent)
Ok((user.clone(), user_ent))
}

/// Validates that the agent can read a list of teams.
Expand All @@ -77,16 +80,16 @@ impl Auth {
let claims = self.claims()?;

if claims.as_user().is_ok() {
let user_ent = self.user(ctx).await?;
let (user, user_ent) = self.user(ctx).await?;
assert::user_registered(ctx, user_ent.user_id).await?;

let team_list_res = op!([ctx] user_team_list {
user_ids: vec![user_ent.user_id.into()],
})
.await?;

let user = unwrap!(team_list_res.users.first());
let user_team_ids = user
let user_teams = unwrap!(team_list_res.users.first());
let user_team_ids = user_teams
.teams
.iter()
.map(|t| Ok(unwrap_ref!(t.team_id).as_uuid()))
Expand All @@ -95,7 +98,7 @@ impl Auth {
.iter()
.all(|team_id| user_team_ids.contains(team_id));

ensure_with!(has_teams, GROUP_NOT_MEMBER);
ensure_with!(has_teams || user.is_admin, GROUP_NOT_MEMBER);

Ok(())
} else if claims.as_game_cloud().is_ok() {
Expand Down Expand Up @@ -140,7 +143,7 @@ impl Auth {
let claims = self.claims()?;

if claims.as_user().is_ok() {
let user_ent = self.user(ctx).await?;
let (user, user_ent) = self.user(ctx).await?;

assert::user_registered(ctx, user_ent.user_id).await?;

Expand Down Expand Up @@ -195,7 +198,7 @@ impl Auth {
let claims = self.claims()?;

if claims.as_user().is_ok() {
let user_ent = self.user(ctx).await?;
let (user, user_ent) = self.user(ctx).await?;

assert::user_registered(ctx, user_ent.user_id).await?;

Expand Down Expand Up @@ -254,7 +257,7 @@ impl Auth {
let claims = self.claims()?;

let (user_id, team_ids, game_ids) = if claims.as_user().is_ok() {
let user_ent = self.user(ctx).await?;
let (_, user_ent) = self.user(ctx).await?;

// Fetch teams associated with user
let teams_res = op!([ctx] user_team_list {
Expand Down Expand Up @@ -369,15 +372,8 @@ impl Auth {
let claims = self.claims()?;

if claims.as_user().is_ok() {
let user_ent = self.user(ctx).await?;

// Get user
let user_res = op!([ctx] user_get {
user_ids: vec![user_ent.user_id.into()]
})
.await?;
let (user, _) = self.user(ctx).await?;

let user = unwrap!(user_res.users.first(), "user not found");
ensure_with!(user.is_admin, IDENTITY_NOT_ADMIN);

Ok(())
Expand Down
11 changes: 7 additions & 4 deletions svc/api/group/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use api_helper::{
auth::{ApiAuth, AuthRateLimitCtx},
util::{as_auth_expired, basic_rate_limit},
};
use proto::claims::Claims;
use proto::{backend, claims::Claims};
use rivet_claims::ClaimsDecode;
use rivet_operation::prelude::*;

Expand Down Expand Up @@ -40,7 +40,10 @@ impl Auth {
.ok_or_else(|| err_code!(API_UNAUTHORIZED, reason = "No bearer token provided."))
}

pub async fn user(&self, ctx: &OperationContext<()>) -> GlobalResult<rivet_claims::ent::User> {
pub async fn user(
&self,
ctx: &OperationContext<()>,
) -> GlobalResult<(backend::user::User, rivet_claims::ent::User)> {
let claims = self.claims()?;
let user_ent = claims.as_user()?;

Expand All @@ -61,15 +64,15 @@ impl Auth {
bail_with!(TOKEN_REVOKED);
}

Ok(user_ent)
Ok((user.clone(), user_ent))
}

/// Validates that the given agent is an admin user.
pub async fn admin(&self, ctx: &OperationContext<()>) -> GlobalResult<()> {
let claims = self.claims()?;

if claims.as_user().is_ok() {
let user_ent = self.user(ctx).await?;
let (_, user_ent) = self.user(ctx).await?;

// Get user
let user_res = op!([ctx] user_get {
Expand Down
52 changes: 26 additions & 26 deletions svc/api/group/src/route/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub async fn profile(
group_id: Uuid,
watch_index: WatchIndexQuery,
) -> GlobalResult<models::GetGroupProfileResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Fetch team data
let teams = op!([ctx] team_get {
Expand Down Expand Up @@ -190,23 +190,23 @@ pub async fn members(
watch_index: WatchIndexQuery,
query: ListMembersQuery,
) -> GlobalResult<models::GetGroupMembersResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (user, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Check if user is a member of this team
let team_list_res = op!([ctx] user_team_list {
user_ids: vec![user_ent.user_id.into()],
})
.await?;

let user = unwrap!(team_list_res.users.first());
let user_team_ids = user
let user_team = unwrap!(team_list_res.users.first());
let user_team_ids = user_team
.teams
.iter()
.map(|t| Ok(unwrap_ref!(t.team_id).as_uuid()))
.collect::<GlobalResult<Vec<_>>>()?;
let has_team = user_team_ids.iter().any(|team_id| &group_id == team_id);

ensure_with!(has_team, GROUP_NOT_MEMBER);
ensure_with!(has_team || user.is_admin, GROUP_NOT_MEMBER);

let team_members_res = op!([ctx] team_member_list {
team_ids: vec![group_id.into()],
Expand Down Expand Up @@ -353,7 +353,7 @@ pub async fn join_requests(
watch_index: WatchIndexQuery,
_query: ListJoinRequestsQuery,
) -> GlobalResult<models::GetGroupJoinRequestsResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Verify the team exists
let (teams_res, team_join_requests_res) = tokio::try_join!(
Expand Down Expand Up @@ -518,7 +518,7 @@ pub async fn update_profile(
group_id: Uuid,
body: models::UpdateGroupProfileRequest,
) -> GlobalResult<models::UpdateGroupProfileResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

let res = op!([ctx] team_get {
team_ids: vec![group_id.into()],
Expand Down Expand Up @@ -564,7 +564,7 @@ pub async fn get_suggested_groups(
ctx: Ctx<Auth>,
_watch_index: WatchIndexQuery,
) -> GlobalResult<models::ListSuggestedGroupsResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Fetch recommendations
let recommend_res = op!([ctx] team_recommend { count: 64 }).await?;
Expand Down Expand Up @@ -593,7 +593,7 @@ pub async fn leave(
group_id: Uuid,
_body: models::LeaveGroupRequest,
) -> GlobalResult<models::LeaveGroupResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Validate the team exists
let teams_res = op!([ctx] team_get {
Expand All @@ -618,7 +618,7 @@ pub async fn create(
ctx: Ctx<Auth>,
body: models::CreateGroupRequest,
) -> GlobalResult<models::CreateGroupResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

let publicity = unwrap!(std::env::var("RIVET_ACCESS_KIND").ok());
match publicity.as_str() {
Expand Down Expand Up @@ -661,7 +661,7 @@ pub async fn request_join(
group_id: Uuid,
_body: models::CreateGroupJoinRequestRequest,
) -> GlobalResult<models::CreateGroupJoinRequestResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Validate the team exists
let teams_res = op!([ctx] team_get {
Expand Down Expand Up @@ -724,7 +724,7 @@ pub async fn resolve_join_request(
identity_id: Uuid,
body: models::ResolveGroupJoinRequestRequest,
) -> GlobalResult<models::ResolveGroupJoinRequestResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Validate the team exists
let teams_res = op!([ctx] team_get {
Expand Down Expand Up @@ -765,7 +765,7 @@ pub async fn search(
_watch_index: WatchIndexQuery,
query: SearchQuery,
) -> GlobalResult<models::SearchGroupsResponse> {
let _user_ent = ctx.auth().user(ctx.op_ctx()).await?;
ctx.auth().user(ctx.op_ctx()).await?;

ensure_with!(
query.limit.map(|v| v != 0).unwrap_or(true),
Expand Down Expand Up @@ -805,7 +805,7 @@ pub async fn validate_profile(
ctx: Ctx<Auth>,
body: models::ValidateGroupProfileRequest,
) -> GlobalResult<models::ValidateGroupProfileResponse> {
let _user_ent = ctx.auth().user(ctx.op_ctx()).await?;
ctx.auth().user(ctx.op_ctx()).await?;

let res = op!([ctx] team_profile_validate {
display_name: body.display_name.clone(),
Expand All @@ -828,7 +828,7 @@ pub async fn transfer_owner(
group_id: Uuid,
body: models::TransferGroupOwnershipRequest,
) -> GlobalResult<models::TransferGroupOwnershipResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (user, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

let new_owner_user_id = Uuid::from_str(body.new_owner_identity_id.as_str())?;

Expand Down Expand Up @@ -856,7 +856,7 @@ pub async fn transfer_owner(

// Verify that new owner is a group member
ensure_with!(
utils::group_member(&ctx, group_id, new_owner_user_id).await?,
utils::group_member(&ctx, group_id, new_owner_user_id).await? || user.is_admin,
GROUP_NOT_MEMBER
);

Expand All @@ -878,7 +878,7 @@ pub async fn prepare_avatar_upload(
ctx: Ctx<Auth>,
body: new_models::GroupPrepareAvatarUploadRequest,
) -> GlobalResult<new_models::GroupPrepareAvatarUploadResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;
assert::user_registered(&ctx, user_ent.user_id).await?;

ensure!(body.content_length >= 0, "Upload invalid");
Expand Down Expand Up @@ -927,7 +927,7 @@ pub async fn complete_avatar_upload(
upload_id: Uuid,
_body: models::CompleteGroupAvatarUploadRequest,
) -> GlobalResult<models::CompleteGroupAvatarUploadResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Validate the team exists
let teams_res = op!([ctx] team_get {
Expand Down Expand Up @@ -959,7 +959,7 @@ pub async fn create_invite(
group_id: Uuid,
body: models::CreateGroupInviteRequest,
) -> GlobalResult<models::CreateGroupInviteResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Validate the team exists
let teams_res = op!([ctx] team_get {
Expand Down Expand Up @@ -999,7 +999,7 @@ pub async fn consume_invite(
code: String,
_body: models::ConsumeGroupInviteRequest,
) -> GlobalResult<models::ConsumeGroupInviteResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

ensure_eq!(code.len(), 8, "invalid code");

Expand Down Expand Up @@ -1078,7 +1078,7 @@ pub async fn get_invite(
code: String,
_watch_index: WatchIndexQuery,
) -> GlobalResult<models::GetGroupInviteResponse> {
let _user_ent = ctx.auth().user(ctx.op_ctx()).await?;
ctx.auth().user(ctx.op_ctx()).await?;

ensure_eq!(code.len(), 8, "invalid code");

Expand Down Expand Up @@ -1121,7 +1121,7 @@ pub async fn kick_member(
identity_id: Uuid,
_body: models::KickGroupMemberRequest,
) -> GlobalResult<models::KickGroupMemberResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (user, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Verify user is not self
ensure_with!(
Expand All @@ -1147,7 +1147,7 @@ pub async fn kick_member(

// Verify that user is a group member
ensure_with!(
utils::group_member(&ctx, group_id, identity_id).await?,
utils::group_member(&ctx, group_id, identity_id).await? || user.is_admin,
GROUP_NOT_MEMBER
);

Expand All @@ -1169,7 +1169,7 @@ pub async fn ban(
identity_id: Uuid,
_body: models::BanGroupIdentityRequest,
) -> GlobalResult<models::BanGroupIdentityResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Verify user is not self
ensure_with!(
Expand Down Expand Up @@ -1210,7 +1210,7 @@ pub async fn unban(
group_id: Uuid,
identity_id: Uuid,
) -> GlobalResult<models::UnbanGroupIdentityResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Verify user is not self
ensure_with!(
Expand Down Expand Up @@ -1263,7 +1263,7 @@ pub async fn bans(
watch_index: WatchIndexQuery,
_query: ListBansQuery,
) -> GlobalResult<models::GetGroupBansResponse> {
let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
let (_, user_ent) = ctx.auth().user(ctx.op_ctx()).await?;

// Verify the team exists
let (teams_res, team_bans_res) = tokio::try_join!(
Expand Down

0 comments on commit 9896b09

Please sign in to comment.