1
0

public.rs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. use chrono::Utc;
  2. use rocket::{
  3. request::{self, FromRequest, Outcome},
  4. Request, Route,
  5. };
  6. use std::collections::HashSet;
  7. use crate::{
  8. api::{EmptyResult, JsonUpcase},
  9. auth,
  10. db::{models::*, DbConn},
  11. mail, CONFIG,
  12. };
  13. pub fn routes() -> Vec<Route> {
  14. routes![ldap_import]
  15. }
  16. #[derive(Deserialize)]
  17. #[allow(non_snake_case)]
  18. struct OrgImportGroupData {
  19. Name: String,
  20. ExternalId: String,
  21. MemberExternalIds: Vec<String>,
  22. }
  23. #[derive(Deserialize)]
  24. #[allow(non_snake_case)]
  25. struct OrgImportUserData {
  26. Email: String,
  27. ExternalId: String,
  28. Deleted: bool,
  29. }
  30. #[derive(Deserialize)]
  31. #[allow(non_snake_case)]
  32. struct OrgImportData {
  33. Groups: Vec<OrgImportGroupData>,
  34. Members: Vec<OrgImportUserData>,
  35. OverwriteExisting: bool,
  36. // LargeImport: bool, // For now this will not be used, upstream uses this to prevent syncs of more then 2000 users or groups without the flag set.
  37. }
  38. #[post("/public/organization/import", data = "<data>")]
  39. async fn ldap_import(data: JsonUpcase<OrgImportData>, token: PublicToken, mut conn: DbConn) -> EmptyResult {
  40. // Most of the logic for this function can be found here
  41. // https://github.com/bitwarden/server/blob/fd892b2ff4547648a276734fb2b14a8abae2c6f5/src/Core/Services/Implementations/OrganizationService.cs#L1797
  42. let org_id = token.0;
  43. let data = data.into_inner().data;
  44. for user_data in &data.Members {
  45. if user_data.Deleted {
  46. // If user is marked for deletion and it exists, revoke it
  47. if let Some(mut user_org) =
  48. UserOrganization::find_by_email_and_org(&user_data.Email, &org_id, &mut conn).await
  49. {
  50. // Only revoke a user if it is not the last confirmed owner
  51. let revoked = if user_org.atype == UserOrgType::Owner
  52. && user_org.status == UserOrgStatus::Confirmed as i32
  53. {
  54. if UserOrganization::count_confirmed_by_org_and_type(&org_id, UserOrgType::Owner, &mut conn).await
  55. <= 1
  56. {
  57. warn!("Can't revoke the last owner");
  58. false
  59. } else {
  60. user_org.revoke()
  61. }
  62. } else {
  63. user_org.revoke()
  64. };
  65. let ext_modified = user_org.set_external_id(Some(user_data.ExternalId.clone()));
  66. if revoked || ext_modified {
  67. user_org.save(&mut conn).await?;
  68. }
  69. }
  70. // If user is part of the organization, restore it
  71. } else if let Some(mut user_org) =
  72. UserOrganization::find_by_email_and_org(&user_data.Email, &org_id, &mut conn).await
  73. {
  74. let restored = user_org.restore();
  75. let ext_modified = user_org.set_external_id(Some(user_data.ExternalId.clone()));
  76. if restored || ext_modified {
  77. user_org.save(&mut conn).await?;
  78. }
  79. } else {
  80. // If user is not part of the organization
  81. let user = match User::find_by_mail(&user_data.Email, &mut conn).await {
  82. Some(user) => user, // exists in vaultwarden
  83. None => {
  84. // User does not exist yet
  85. let mut new_user = User::new(user_data.Email.clone());
  86. new_user.save(&mut conn).await?;
  87. if !CONFIG.mail_enabled() {
  88. let invitation = Invitation::new(&new_user.email);
  89. invitation.save(&mut conn).await?;
  90. }
  91. new_user
  92. }
  93. };
  94. let user_org_status = if CONFIG.mail_enabled() || user.password_hash.is_empty() {
  95. UserOrgStatus::Invited as i32
  96. } else {
  97. UserOrgStatus::Accepted as i32 // Automatically mark user as accepted if no email invites
  98. };
  99. let mut new_org_user = UserOrganization::new(user.uuid.clone(), org_id.clone());
  100. new_org_user.set_external_id(Some(user_data.ExternalId.clone()));
  101. new_org_user.access_all = false;
  102. new_org_user.atype = UserOrgType::User as i32;
  103. new_org_user.status = user_org_status;
  104. new_org_user.save(&mut conn).await?;
  105. if CONFIG.mail_enabled() {
  106. let (org_name, org_email) = match Organization::find_by_uuid(&org_id, &mut conn).await {
  107. Some(org) => (org.name, org.billing_email),
  108. None => err!("Error looking up organization"),
  109. };
  110. mail::send_invite(
  111. &user_data.Email,
  112. &user.uuid,
  113. Some(org_id.clone()),
  114. Some(new_org_user.uuid),
  115. &org_name,
  116. Some(org_email),
  117. )
  118. .await?;
  119. }
  120. }
  121. }
  122. if CONFIG.org_groups_enabled() {
  123. for group_data in &data.Groups {
  124. let group_uuid = match Group::find_by_external_id(&group_data.ExternalId, &mut conn).await {
  125. Some(group) => group.uuid,
  126. None => {
  127. let mut group =
  128. Group::new(org_id.clone(), group_data.Name.clone(), false, Some(group_data.ExternalId.clone()));
  129. group.save(&mut conn).await?;
  130. group.uuid
  131. }
  132. };
  133. GroupUser::delete_all_by_group(&group_uuid, &mut conn).await?;
  134. for ext_id in &group_data.MemberExternalIds {
  135. if let Some(user_org) = UserOrganization::find_by_external_id_and_org(ext_id, &org_id, &mut conn).await
  136. {
  137. let mut group_user = GroupUser::new(group_uuid.clone(), user_org.uuid.clone());
  138. group_user.save(&mut conn).await?;
  139. }
  140. }
  141. }
  142. } else {
  143. warn!("Group support is disabled, groups will not be imported!");
  144. }
  145. // If this flag is enabled, any user that isn't provided in the Users list will be removed (by default they will be kept unless they have Deleted == true)
  146. if data.OverwriteExisting {
  147. // Generate a HashSet to quickly verify if a member is listed or not.
  148. let sync_members: HashSet<String> = data.Members.into_iter().map(|m| m.ExternalId).collect();
  149. for user_org in UserOrganization::find_by_org(&org_id, &mut conn).await {
  150. if let Some(ref user_external_id) = user_org.external_id {
  151. if !sync_members.contains(user_external_id) {
  152. if user_org.atype == UserOrgType::Owner && user_org.status == UserOrgStatus::Confirmed as i32 {
  153. // Removing owner, check that there is at least one other confirmed owner
  154. if UserOrganization::count_confirmed_by_org_and_type(&org_id, UserOrgType::Owner, &mut conn)
  155. .await
  156. <= 1
  157. {
  158. warn!("Can't delete the last owner");
  159. continue;
  160. }
  161. }
  162. user_org.delete(&mut conn).await?;
  163. }
  164. }
  165. }
  166. }
  167. Ok(())
  168. }
  169. pub struct PublicToken(String);
  170. #[rocket::async_trait]
  171. impl<'r> FromRequest<'r> for PublicToken {
  172. type Error = &'static str;
  173. async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
  174. let headers = request.headers();
  175. // Get access_token
  176. let access_token: &str = match headers.get_one("Authorization") {
  177. Some(a) => match a.rsplit("Bearer ").next() {
  178. Some(split) => split,
  179. None => err_handler!("No access token provided"),
  180. },
  181. None => err_handler!("No access token provided"),
  182. };
  183. // Check JWT token is valid and get device and user from it
  184. let claims = match auth::decode_api_org(access_token) {
  185. Ok(claims) => claims,
  186. Err(_) => err_handler!("Invalid claim"),
  187. };
  188. // Check if time is between claims.nbf and claims.exp
  189. let time_now = Utc::now().naive_utc().timestamp();
  190. if time_now < claims.nbf {
  191. err_handler!("Token issued in the future");
  192. }
  193. if time_now > claims.exp {
  194. err_handler!("Token expired");
  195. }
  196. // Check if claims.iss is host|claims.scope[0]
  197. let host = match auth::Host::from_request(request).await {
  198. Outcome::Success(host) => host,
  199. _ => err_handler!("Error getting Host"),
  200. };
  201. let complete_host = format!("{}|{}", host.host, claims.scope[0]);
  202. if complete_host != claims.iss {
  203. err_handler!("Token not issued by this server");
  204. }
  205. // Check if claims.sub is org_api_key.uuid
  206. // Check if claims.client_sub is org_api_key.org_uuid
  207. let conn = match DbConn::from_request(request).await {
  208. Outcome::Success(conn) => conn,
  209. _ => err_handler!("Error getting DB"),
  210. };
  211. let org_uuid = match claims.client_id.strip_prefix("organization.") {
  212. Some(uuid) => uuid,
  213. None => err_handler!("Malformed client_id"),
  214. };
  215. let org_api_key = match OrganizationApiKey::find_by_org_uuid(org_uuid, &conn).await {
  216. Some(org_api_key) => org_api_key,
  217. None => err_handler!("Invalid client_id"),
  218. };
  219. if org_api_key.org_uuid != claims.client_sub {
  220. err_handler!("Token not issued for this org");
  221. }
  222. if org_api_key.uuid != claims.sub {
  223. err_handler!("Token not issued for this client");
  224. }
  225. Outcome::Success(PublicToken(claims.client_sub))
  226. }
  227. }