Skip to content

Commit

Permalink
improve check if current user has access via group
Browse files Browse the repository at this point in the history
instead of returning the two lists of member ids and later checking if
they contain the uuid of the current user, we really only care if
the current user has full access via a group or if they have
access to a given collection via a group
  • Loading branch information
stefan0xC committed Jan 5, 2024
1 parent 600517c commit bcae739
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 42 deletions.
53 changes: 25 additions & 28 deletions src/api/core/organizations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,50 +322,47 @@ async fn get_org_collections_details(org_id: &str, headers: ManagerHeadersLoose,
};

let coll_users = CollectionUser::find_by_organization(org_id, &mut conn).await;
// uuids of users in groups having access to all collections
let has_full_access_via_group = if CONFIG.org_groups_enabled() {
GroupUser::get_members_of_full_access_groups(org_id, &mut conn).await
} else {
vec![]
};

let has_full_access = user_org.access_all || has_full_access_via_group.contains(&user_org.uuid);
let has_full_access_via_group =
CONFIG.org_groups_enabled() || GroupUser::has_full_access_by_member(org_id, &user_org.uuid, &mut conn).await;

for col in Collection::find_by_organization(org_id, &mut conn).await {
let groups: Vec<Value> = if CONFIG.org_groups_enabled() {
CollectionGroup::find_by_collection(&col.uuid, &mut conn)
.await
.iter()
.map(|collection_group| {
SelectionReadOnly::to_collection_group_details_read_only(collection_group).to_json()
})
.collect()
} else {
// The Bitwarden clients seem to call this API regardless of whether groups are enabled,
// so just act as if there are no groups.
Vec::with_capacity(0)
};
// check if current user has full access to the organization (either directly or via any group)
let has_full_access = user_org.access_all || has_full_access_via_group;

for col in Collection::find_by_organization(org_id, &mut conn).await {
let mut assigned = has_full_access;

// get the users assigned directly to the given collection
let users: Vec<Value> = coll_users
.iter()
.filter(|collection_user| collection_user.collection_uuid == col.uuid)
.map(|collection_user| {
// Remember `user_uuid` is swapped here with the `user_org.uuid` with a join during the `CollectionUser::find_by_organization` call.
// We check here if the current user is assigned to this collection or not.
// check if the current user is assigned to this collection
if collection_user.user_uuid == user_org.uuid {
assigned = true;
}
SelectionReadOnly::to_collection_user_details_read_only(collection_user).to_json()
})
.collect();

// if the current user is not assigned and groups are enabled,
// get the group details for the given collection
let groups: Vec<Value> = if CONFIG.org_groups_enabled() {
CollectionGroup::find_by_collection(&col.uuid, &mut conn)
.await
.iter()
.map(|collection_group| {
SelectionReadOnly::to_collection_group_details_read_only(collection_group).to_json()
})
.collect()
} else {
Vec::with_capacity(0)
};

// if the current user does not have full_acces and is also not assigned via a collection
// check if they have access to the given collection via a group
if !assigned && CONFIG.org_groups_enabled()
{
assigned = GroupUser::get_group_members_for_collection(&col.uuid, &mut conn).await.contains(&user_org.uuid);
}
if !assigned && CONFIG.org_groups_enabled() {
assigned = GroupUser::has_access_to_collection_by_member(&col.uuid, &user_org.uuid, &mut conn).await;
}

let mut json_object = col.to_json();
json_object["Assigned"] = json!(assigned);
Expand Down
28 changes: 14 additions & 14 deletions src/db/models/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,37 +486,37 @@ impl GroupUser {
}}
}

pub async fn get_group_members_for_collection(collection_uuid: &str, conn: &mut DbConn) -> Vec<String> {
pub async fn has_access_to_collection_by_member(
collection_uuid: &str,
member_uuid: &str,
conn: &mut DbConn,
) -> bool {
db_run! { conn: {
groups_users::table
.inner_join(collections_groups::table.on(
collections_groups::groups_uuid.eq(groups_users::groups_uuid)
))
.filter(collections_groups::collections_uuid.eq(collection_uuid))
.select(groups_users::users_organizations_uuid)
.distinct()
.load::<String>(conn)
.expect("Error loading group users for collection")
.filter(groups_users::users_organizations_uuid.eq(member_uuid))
.count()
.first::<i64>(conn)
.unwrap_or(0) != 0
}}
.into_iter()
.collect()
}

pub async fn get_members_of_full_access_groups(org_uuid: &str, conn: &mut DbConn) -> Vec<String> {
pub async fn has_full_access_by_member(org_uuid: &str, member_uuid: &str, conn: &mut DbConn) -> bool {
db_run! { conn: {
groups_users::table
.inner_join(groups::table.on(
groups::uuid.eq(groups_users::groups_uuid)
))
.filter(groups::organizations_uuid.eq(org_uuid))
.filter(groups::access_all.eq(true))
.select(groups_users::users_organizations_uuid)
.distinct()
.load::<String>(conn)
.expect("Error loading all access group users for organization")
.filter(groups_users::users_organizations_uuid.eq(member_uuid))
.count()
.first::<i64>(conn)
.unwrap_or(0) != 0
}}
.into_iter()
.collect()
}

pub async fn update_user_revision(&self, conn: &mut DbConn) {
Expand Down

0 comments on commit bcae739

Please sign in to comment.