Browse Source

let invited members access OrgMemberHeaders (#5461)

pull/5477/head
Stefan Melmuk 4 days ago
committed by GitHub
parent
commit
2c549984c0
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 53
      src/auth.rs
  2. 14
      src/db/models/organization.rs

53
src/auth.rs

@ -542,10 +542,29 @@ pub struct OrgHeaders {
pub device: Device, pub device: Device,
pub user: User, pub user: User,
pub membership_type: MembershipType, pub membership_type: MembershipType,
pub membership_status: MembershipStatus,
pub membership: Membership, pub membership: Membership,
pub ip: ClientIp, pub ip: ClientIp,
} }
impl OrgHeaders {
fn is_member(&self) -> bool {
// NOTE: we don't care about MembershipStatus at the moment because this is only used
// where an invited, accepted or confirmed user is expected if this ever changes or
// if from_i32 is changed to return Some(Revoked) this check needs to be changed accordingly
self.membership_type >= MembershipType::User
}
fn is_confirmed_and_admin(&self) -> bool {
self.membership_status == MembershipStatus::Confirmed && self.membership_type >= MembershipType::Admin
}
fn is_confirmed_and_manager(&self) -> bool {
self.membership_status == MembershipStatus::Confirmed && self.membership_type >= MembershipType::Manager
}
fn is_confirmed_and_owner(&self) -> bool {
self.membership_status == MembershipStatus::Confirmed && self.membership_type == MembershipType::Owner
}
}
#[rocket::async_trait] #[rocket::async_trait]
impl<'r> FromRequest<'r> for OrgHeaders { impl<'r> FromRequest<'r> for OrgHeaders {
type Error = &'static str; type Error = &'static str;
@ -574,15 +593,8 @@ impl<'r> FromRequest<'r> for OrgHeaders {
}; };
let user = headers.user; let user = headers.user;
let membership = match Membership::find_by_user_and_org(&user.uuid, &org_id, &mut conn).await { let Some(membership) = Membership::find_by_user_and_org(&user.uuid, &org_id, &mut conn).await else {
Some(member) => { err_handler!("The current user isn't member of the organization");
if member.status == MembershipStatus::Confirmed as i32 {
member
} else {
err_handler!("The current user isn't confirmed member of the organization")
}
}
None => err_handler!("The current user isn't member of the organization"),
}; };
Outcome::Success(Self { Outcome::Success(Self {
@ -590,13 +602,22 @@ impl<'r> FromRequest<'r> for OrgHeaders {
device: headers.device, device: headers.device,
user, user,
membership_type: { membership_type: {
if let Some(org_usr_type) = MembershipType::from_i32(membership.atype) { if let Some(member_type) = MembershipType::from_i32(membership.atype) {
org_usr_type member_type
} else { } else {
// This should only happen if the DB is corrupted // This should only happen if the DB is corrupted
err_handler!("Unknown user type in the database") err_handler!("Unknown user type in the database")
} }
}, },
membership_status: {
if let Some(member_status) = MembershipStatus::from_i32(membership.status) {
// NOTE: add additional check for revoked if from_i32 is ever changed
// to return Revoked status.
member_status
} else {
err_handler!("User status is either revoked or invalid.")
}
},
membership, membership,
ip: headers.ip, ip: headers.ip,
}) })
@ -621,7 +642,7 @@ impl<'r> FromRequest<'r> for AdminHeaders {
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let headers = try_outcome!(OrgHeaders::from_request(request).await); let headers = try_outcome!(OrgHeaders::from_request(request).await);
if headers.membership_type >= MembershipType::Admin { if headers.is_confirmed_and_admin() {
Outcome::Success(Self { Outcome::Success(Self {
host: headers.host, host: headers.host,
device: headers.device, device: headers.device,
@ -683,7 +704,7 @@ impl<'r> FromRequest<'r> for ManagerHeaders {
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let headers = try_outcome!(OrgHeaders::from_request(request).await); let headers = try_outcome!(OrgHeaders::from_request(request).await);
if headers.membership_type >= MembershipType::Manager { if headers.is_confirmed_and_manager() {
match get_col_id(request) { match get_col_id(request) {
Some(col_id) => { Some(col_id) => {
let mut conn = match DbConn::from_request(request).await { let mut conn = match DbConn::from_request(request).await {
@ -738,7 +759,7 @@ impl<'r> FromRequest<'r> for ManagerHeadersLoose {
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let headers = try_outcome!(OrgHeaders::from_request(request).await); let headers = try_outcome!(OrgHeaders::from_request(request).await);
if headers.membership_type >= MembershipType::Manager { if headers.is_confirmed_and_manager() {
Outcome::Success(Self { Outcome::Success(Self {
host: headers.host, host: headers.host,
device: headers.device, device: headers.device,
@ -801,7 +822,7 @@ impl<'r> FromRequest<'r> for OwnerHeaders {
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let headers = try_outcome!(OrgHeaders::from_request(request).await); let headers = try_outcome!(OrgHeaders::from_request(request).await);
if headers.membership_type == MembershipType::Owner { if headers.is_confirmed_and_owner() {
Outcome::Success(Self { Outcome::Success(Self {
device: headers.device, device: headers.device,
user: headers.user, user: headers.user,
@ -826,7 +847,7 @@ impl<'r> FromRequest<'r> for OrgMemberHeaders {
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let headers = try_outcome!(OrgHeaders::from_request(request).await); let headers = try_outcome!(OrgHeaders::from_request(request).await);
if headers.membership_type >= MembershipType::User { if headers.is_member() {
Outcome::Success(Self { Outcome::Success(Self {
host: headers.host, host: headers.host,
user: headers.user, user: headers.user,

14
src/db/models/organization.rs

@ -55,6 +55,7 @@ db_object! {
} }
// https://github.com/bitwarden/server/blob/b86a04cef9f1e1b82cf18e49fc94e017c641130c/src/Core/Enums/OrganizationUserStatusType.cs // https://github.com/bitwarden/server/blob/b86a04cef9f1e1b82cf18e49fc94e017c641130c/src/Core/Enums/OrganizationUserStatusType.cs
#[derive(PartialEq)]
pub enum MembershipStatus { pub enum MembershipStatus {
Revoked = -1, Revoked = -1,
Invited = 0, Invited = 0,
@ -62,6 +63,19 @@ pub enum MembershipStatus {
Confirmed = 2, Confirmed = 2,
} }
impl MembershipStatus {
pub fn from_i32(status: i32) -> Option<Self> {
match status {
0 => Some(Self::Invited),
1 => Some(Self::Accepted),
2 => Some(Self::Confirmed),
// NOTE: we don't care about revoked members where this is used
// if this ever changes also adapt the OrgHeaders check.
_ => None,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, num_derive::FromPrimitive)] #[derive(Copy, Clone, PartialEq, Eq, num_derive::FromPrimitive)]
pub enum MembershipType { pub enum MembershipType {
Owner = 0, Owner = 0,

Loading…
Cancel
Save