Store the impersonator id on access tokens created via ZED_IMPERSONATE

* Use the impersonator id to prevent these tokens from counting
  against the impersonated user when limiting the users' total
  of access tokens.
* When connecting using an access token with an impersonator
  add the impersonator as a field to the tracing span that wraps
  the task for that connection.
* Disallow impersonating users via the admin API token in production,
  because when using the admin API token, we aren't able to identify
  the impersonator.

Co-authored-by: Marshall <marshall@zed.dev>
This commit is contained in:
Max Brunsfeld 2024-01-17 15:46:36 -08:00
parent 9521f49160
commit ab1bea515c
9 changed files with 198 additions and 39 deletions

View file

@ -6,6 +6,7 @@ impl Database {
pub async fn create_access_token(
&self,
user_id: UserId,
impersonator_id: Option<UserId>,
access_token_hash: &str,
max_access_token_count: usize,
) -> Result<AccessTokenId> {
@ -14,19 +15,28 @@ impl Database {
let token = access_token::ActiveModel {
user_id: ActiveValue::set(user_id),
impersonator_id: ActiveValue::set(impersonator_id),
hash: ActiveValue::set(access_token_hash.into()),
..Default::default()
}
.insert(&*tx)
.await?;
let existing_token_filter = if let Some(impersonator_id) = impersonator_id {
access_token::Column::ImpersonatorId.eq(impersonator_id)
} else {
access_token::Column::UserId
.eq(user_id)
.and(access_token::Column::ImpersonatorId.is_null())
};
access_token::Entity::delete_many()
.filter(
access_token::Column::Id.in_subquery(
Query::select()
.column(access_token::Column::Id)
.from(access_token::Entity)
.and_where(access_token::Column::UserId.eq(user_id))
.cond_where(existing_token_filter)
.order_by(access_token::Column::Id, sea_orm::Order::Desc)
.limit(10000)
.offset(max_access_token_count as u64)