Skip to content

Commit

Permalink
Groups should not contain duplicates
Browse files Browse the repository at this point in the history
  • Loading branch information
augustuswm committed Oct 2, 2023
1 parent 9a80692 commit 2c159fc
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 32 deletions.
18 changes: 10 additions & 8 deletions rfd-api/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use rfd_model::{
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, sync::Arc};
use std::{collections::{HashMap, BTreeSet}, sync::Arc};
use tap::TapFallible;
use thiserror::Error;
use tracing::{info_span, instrument, Instrument};
Expand Down Expand Up @@ -332,7 +332,7 @@ impl ApiContext {
let groups = AccessGroupStore::list(
&*self.storage,
AccessGroupFilter {
id: Some(user.groups.clone()),
id: Some(user.groups.iter().copied().collect()),
..Default::default()
},
&ListPagination::default().limit(UNLIMITED),
Expand Down Expand Up @@ -572,9 +572,9 @@ impl ApiContext {
}
}

async fn get_mapped_fields(&self, info: &UserInfo) -> Result<(ApiPermissions, Vec<Uuid>), StoreError> {
async fn get_mapped_fields(&self, info: &UserInfo) -> Result<(ApiPermissions, BTreeSet<Uuid>), StoreError> {
let mut mapped_permissions = ApiPermissions::new();
let mut mapped_groups = vec![];
let mut mapped_groups = BTreeSet::new();

// We optimistically load mappers here. We do not want to take a lock on the mappers and
// instead handle mappers that become depleted before we can evaluate them at evaluation
Expand Down Expand Up @@ -623,7 +623,7 @@ impl ApiContext {
&self,
api_user_id: Uuid,
mut mapped_permissions: ApiPermissions,
mut mapped_groups: Vec<Uuid>,
mut mapped_groups: BTreeSet<Uuid>,
) -> Result<User, ApiError> {
match self.get_api_user(&api_user_id).await? {
Some(api_user) => {
Expand Down Expand Up @@ -996,7 +996,7 @@ impl ApiContext {

Ok(if let Some(user) = user {
let mut update: NewApiUser<ApiPermission> = user.into();
update.groups.push(*group_id);
update.groups.insert(*group_id);

Some(ApiUserStore::upsert(&*self.storage, update).await?)
} else {
Expand Down Expand Up @@ -1078,7 +1078,7 @@ mod tests {
storage::{AccessGroupFilter, ListPagination, MockAccessGroupStore, MockApiUserStore},
AccessGroup, ApiUser,
};
use std::{ops::Add, sync::Arc};
use std::{ops::Add, sync::Arc, collections::BTreeSet};
use uuid::Uuid;

use crate::{
Expand Down Expand Up @@ -1146,10 +1146,12 @@ mod tests {

let user_id = Uuid::new_v4();
let user_permissions: ApiPermissions = vec![ApiPermission::GetRfd(5)].into();
let mut groups = BTreeSet::new();
groups.insert(group_id);
let user = ApiUser {
id: user_id,
permissions: user_permissions.clone(),
groups: vec![group_id],
groups,
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
Expand Down
22 changes: 12 additions & 10 deletions rfd-api/src/endpoints/api_user.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::BTreeSet;

use chrono::{DateTime, Utc};
use dropshot::{
endpoint, HttpError, HttpResponseCreated, HttpResponseOk, Path, RequestContext, TypedBody,
Expand Down Expand Up @@ -87,7 +89,7 @@ async fn get_api_user_op(
#[derive(Debug, Clone, PartialEq, Deserialize, JsonSchema)]
pub struct ApiUserUpdateParams {
permissions: ApiPermissions,
groups: Vec<Uuid>,
groups: BTreeSet<Uuid>,
}

/// Create a new user with a given set of permissions
Expand Down Expand Up @@ -470,7 +472,7 @@ pub async fn remove_api_user_from_group(

#[cfg(test)]
mod tests {
use std::sync::Arc;
use std::{sync::Arc, collections::BTreeSet};

use chrono::{Duration, Utc};
use http::StatusCode;
Expand Down Expand Up @@ -499,7 +501,7 @@ mod tests {
ApiUser {
id: Uuid::new_v4(),
permissions: vec![].into(),
groups: vec![],
groups: BTreeSet::new(),
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
Expand All @@ -510,12 +512,12 @@ mod tests {
async fn test_create_api_user_permissions() {
let successful_update = ApiUserUpdateParams {
permissions: vec![ApiPermission::CreateApiUser.into()].into(),
groups: vec![],
groups: BTreeSet::new(),
};

let failure_update = ApiUserUpdateParams {
permissions: vec![ApiPermission::GetApiUserAll.into()].into(),
groups: vec![],
groups: BTreeSet::new(),
};

let mut store = MockApiUserStore::new();
Expand All @@ -528,7 +530,7 @@ mod tests {
Ok(ApiUser {
id: user.id,
permissions: user.permissions,
groups: vec![],
groups: BTreeSet::new(),
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
Expand Down Expand Up @@ -586,13 +588,13 @@ mod tests {
let success_id = Uuid::new_v4();
let successful_update = ApiUserUpdateParams {
permissions: Vec::new().into(),
groups: vec![],
groups: BTreeSet::new(),
};

let failure_id = Uuid::new_v4();
let failure_update = ApiUserUpdateParams {
permissions: Vec::new().into(),
groups: vec![],
groups: BTreeSet::new(),
};

let mut store = MockApiUserStore::new();
Expand All @@ -603,7 +605,7 @@ mod tests {
Ok(ApiUser {
id: user.id,
permissions: user.permissions,
groups: vec![],
groups: BTreeSet::new(),
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
Expand Down Expand Up @@ -821,7 +823,7 @@ mod tests {
let api_user = ApiUser {
id: api_user_id,
permissions: vec![ApiPermission::GetApiUserToken(api_user_id).into()].into(),
groups: vec![],
groups: BTreeSet::new(),
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
Expand Down
6 changes: 3 additions & 3 deletions rfd-api/src/endpoints/login/oauth/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ async fn delete_oauth_client_redirect_uri_op(

#[cfg(test)]
mod tests {
use std::sync::{Arc, Mutex};
use std::{sync::{Arc, Mutex}, collections::BTreeSet};

use chrono::Utc;
use rfd_model::{
Expand All @@ -338,7 +338,7 @@ mod tests {
ApiUser {
id: Uuid::new_v4(),
permissions: vec![ApiPermission::CreateOAuthClient].into(),
groups: vec![],
groups: BTreeSet::new(),
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
Expand All @@ -352,7 +352,7 @@ mod tests {
Ok(ApiUser {
id: user.id,
permissions: user.permissions,
groups: vec![],
groups: user.groups,
created_at: Utc::now(),
updated_at: Utc::now(),
deleted_at: None,
Expand Down
12 changes: 7 additions & 5 deletions rfd-api/src/mapper.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::BTreeSet;

use async_trait::async_trait;
use rfd_model::storage::StoreError;
use serde::{Deserialize, Serialize};
Expand All @@ -12,7 +14,7 @@ pub trait MapperRule: Send + Sync {
ctx: &ApiContext,
user: &UserInfo,
) -> Result<ApiPermissions, StoreError>;
async fn groups_for(&self, ctx: &ApiContext, user: &UserInfo) -> Result<Vec<Uuid>, StoreError>;
async fn groups_for(&self, ctx: &ApiContext, user: &UserInfo) -> Result<BTreeSet<Uuid>, StoreError>;
}

#[derive(Debug, Serialize)]
Expand Down Expand Up @@ -45,7 +47,7 @@ impl MapperRule for EmailDomainMapper {
Ok(ApiPermissions::new())
}

async fn groups_for(&self, ctx: &ApiContext, user: &UserInfo) -> Result<Vec<Uuid>, StoreError> {
async fn groups_for(&self, ctx: &ApiContext, user: &UserInfo) -> Result<BTreeSet<Uuid>, StoreError> {
let has_email_in_domain = user
.verified_emails
.iter()
Expand All @@ -63,10 +65,10 @@ impl MapperRule for EmailDomainMapper {
None
}
})
.collect::<Vec<_>>();
.collect();
Ok(groups)
} else {
Ok(vec![])
Ok(BTreeSet::new())
}
}
}
Expand All @@ -83,7 +85,7 @@ impl MapperRule for MappingRules {
}
}

async fn groups_for(&self, ctx: &ApiContext, user: &UserInfo) -> Result<Vec<Uuid>, StoreError> {
async fn groups_for(&self, ctx: &ApiContext, user: &UserInfo) -> Result<BTreeSet<Uuid>, StoreError> {
match self {
Self::EmailDomain(rule) => rule.groups_for(ctx, user).await,
}
Expand Down
4 changes: 2 additions & 2 deletions rfd-model/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::BTreeMap, fmt::Display};
use std::{collections::{BTreeMap, BTreeSet}, fmt::Display};

use chrono::{DateTime, Utc};
use db::{
Expand Down Expand Up @@ -164,7 +164,7 @@ impl From<JobModel> for Job {
pub struct ApiUser<T: Ord> {
pub id: Uuid,
pub permissions: Permissions<T>,
pub groups: Vec<Uuid>,
pub groups: BTreeSet<Uuid>,
#[partial(NewApiUser(skip))]
pub created_at: DateTime<Utc>,
#[partial(NewApiUser(skip))]
Expand Down
2 changes: 1 addition & 1 deletion rfd-model/src/storage/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ where
.values((
api_user::id.eq(user.id),
api_user::permissions.eq(user.permissions.clone()),
api_user::groups.eq(user.groups.clone()),
api_user::groups.eq(user.groups.into_iter().collect::<Vec<_>>()),
))
.on_conflict(api_user::id)
.do_update()
Expand Down
8 changes: 5 additions & 3 deletions rfd-model/tests/postgres.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::BTreeSet;

use chrono::{Duration, Utc};
use diesel::{
migration::{Migration, MigrationSource},
Expand Down Expand Up @@ -126,7 +128,7 @@ async fn test_api_user() {
NewApiUser {
id: api_user_id,
permissions: vec![TestPermission::CreateApiKey(api_user_id).into()].into(),
groups: vec![],
groups: BTreeSet::new(),
},
)
.await
Expand All @@ -146,7 +148,7 @@ async fn test_api_user() {
NewApiUser {
id: api_user_id,
permissions: vec![TestPermission::CreateApiKey(api_user_id).into()].into(),
groups: vec![],
groups: BTreeSet::new(),
},
)
.await
Expand All @@ -165,7 +167,7 @@ async fn test_api_user() {
TestPermission::DeleteApiKey(api_user_id).into(),
]
.into(),
groups: vec![],
groups: BTreeSet::new(),
},
)
.await
Expand Down

0 comments on commit 2c159fc

Please sign in to comment.