mirror of
				https://github.com/dani-garcia/vaultwarden.git
				synced 2025-10-31 02:08:20 +02:00 
			
		
		
		
	let invited members access OrgMemberHeaders (#5461)
This commit is contained in:
		
							
								
								
									
										53
									
								
								src/auth.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, | ||||||
|   | |||||||
| @@ -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, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user