Fix get_groups_data when not using full_access

This commit is contained in:
Daniel García
2026-07-24 16:20:34 +02:00
parent 94a798e9dd
commit 5f03e74feb
2 changed files with 53 additions and 4 deletions
+10 -4
View File
@@ -2463,13 +2463,19 @@ async fn get_groups_data(
err!("Organization not found", "Organization id's do not match"); err!("Organization not found", "Organization id's do not match");
} }
// For now, both the group list and the details view require full access to the organization // The details view (group→collection/user mappings) needs full org access; the plain list only
// (directly or via a group). Bitwarden also lets a manager of a specific collection read the // needs manage access to a collection, so a manager of a collection (directly or via a group)
// plain list (to assign groups); handling that case is left for a follow-up. // can load it to assign groups.
let has_full_access = headers.membership.has_full_access() let has_full_access = headers.membership.has_full_access()
|| (CONFIG.org_groups_enabled() || (CONFIG.org_groups_enabled()
&& GroupUser::has_full_access_by_member(&org_id, &headers.membership.uuid, &conn).await); && GroupUser::has_full_access_by_member(&org_id, &headers.membership.uuid, &conn).await);
if !has_full_access { let allowed = if details {
has_full_access
} else {
has_full_access
|| Collection::has_manageable_collection_by_user(&org_id, &headers.membership.user_uuid, &conn).await
};
if !allowed {
err_code!("Resource not found.", "User does not have access", rocket::http::Status::NotFound.code); err_code!("Resource not found.", "User does not have access", rocket::http::Status::NotFound.code);
} }
+43
View File
@@ -623,6 +623,49 @@ impl Collection {
pub async fn is_manageable_by_user(&self, user_uuid: &UserId, conn: &DbConn) -> bool { pub async fn is_manageable_by_user(&self, user_uuid: &UserId, conn: &DbConn) -> bool {
Self::is_coll_manageable_by_user(&self.uuid, user_uuid, conn).await Self::is_coll_manageable_by_user(&self.uuid, user_uuid, conn).await
} }
// Whether the user has manage access to at least one collection in the org, directly or via a
// group. Org-scoped counterpart of is_coll_manageable_by_user.
pub async fn has_manageable_collection_by_user(
org_uuid: &OrganizationId,
user_uuid: &UserId,
conn: &DbConn,
) -> bool {
let org_uuid = org_uuid.to_string();
let user_uuid = user_uuid.to_string();
conn.run(move |conn| {
collections::table
.left_join(
users_collections::table.on(users_collections::collection_uuid
.eq(collections::uuid)
.and(users_collections::user_uuid.eq(user_uuid.clone()))),
)
.left_join(
users_organizations::table.on(collections::org_uuid
.eq(users_organizations::org_uuid)
.and(users_organizations::user_uuid.eq(user_uuid))),
)
.left_join(groups_users::table.on(groups_users::users_organizations_uuid.eq(users_organizations::uuid)))
.left_join(
collections_groups::table.on(collections_groups::groups_uuid
.eq(groups_users::groups_uuid)
.and(collections_groups::collections_uuid.eq(collections::uuid))),
)
.filter(collections::org_uuid.eq(&org_uuid))
.filter(
// Manage permission on a collection assigned directly or via a group.
users_collections::manage
.eq(true)
.or(collections_groups::manage.eq(true)),
)
.count()
.first::<i64>(conn)
.ok()
.unwrap_or(0)
!= 0
})
.await
}
} }
/// Database methods /// Database methods