vw_small

Hardened fork of Vaultwarden (https://github.com/dani-garcia/vaultwarden) with fewer features.
git clone https://git.philomathiclife.com/repos/vw_small
Log | Files | Refs | README

commit 4d50014e355d806c6b13ef349899ad1546db0982
parent ed97725c8b389b4b760d84130bcbac283126bf70
Author: Miroslav Prasil <miroslav@prasil.info>
Date:   Wed, 30 May 2018 13:28:31 +0100

Implement request guards for organization

Diffstat:
Msrc/api/core/organizations.rs | 24+++++++-----------------
Msrc/auth.rs | 102++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 108 insertions(+), 18 deletions(-)

diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs @@ -6,7 +6,7 @@ use db::DbConn; use db::models::*; use api::{PasswordData, JsonResult, EmptyResult, NumberOrString}; -use auth::Headers; +use auth::{Headers, AdminHeaders, OwnerHeaders}; #[derive(Deserialize)] @@ -82,11 +82,7 @@ fn delete_organization(org_id: String, data: Json<PasswordData>, headers: Header } #[get("/organizations/<org_id>")] -fn get_organization(org_id: String, headers: Headers, conn: DbConn) -> JsonResult { - if UserOrganization::find_by_user_and_org( &headers.user.uuid, &org_id, &conn).is_none() { - err!("User not in Organization or Organization doesn't exist") - } - +fn get_organization(org_id: String, headers: OwnerHeaders, conn: DbConn) -> JsonResult { match Organization::find_by_uuid(&org_id, &conn) { Some(organization) => Ok(Json(organization.to_json())), None => err!("Can't find organization details") @@ -132,7 +128,7 @@ fn get_user_collections(headers: Headers, conn: DbConn) -> JsonResult { } #[get("/organizations/<org_id>/collections")] -fn get_org_collections(org_id: String, headers: Headers, conn: DbConn) -> JsonResult { +fn get_org_collections(org_id: String, headers: AdminHeaders, conn: DbConn) -> JsonResult { Ok(Json(json!({ "Data": Collection::find_by_organization(&org_id, &conn) @@ -226,7 +222,7 @@ fn post_organization_collection_delete(org_id: String, col_id: String, headers: } #[get("/organizations/<org_id>/collections/<coll_id>/details")] -fn get_org_collection_detail(org_id: String, coll_id: String, headers: Headers, conn: DbConn) -> JsonResult { +fn get_org_collection_detail(org_id: String, coll_id: String, headers: AdminHeaders, conn: DbConn) -> JsonResult { match Collection::find_by_uuid_and_user(&coll_id, &headers.user.uuid, &conn) { None => err!("Collection not found"), Some(collection) => Ok(Json(collection.to_json())) @@ -234,7 +230,7 @@ fn get_org_collection_detail(org_id: String, coll_id: String, headers: Headers, } #[get("/organizations/<org_id>/collections/<coll_id>/users")] -fn get_collection_users(org_id: String, coll_id: String, headers: Headers, conn: DbConn) -> JsonResult { +fn get_collection_users(org_id: String, coll_id: String, headers: AdminHeaders, conn: DbConn) -> JsonResult { // Get org and collection, check that collection is from org // Get the users from collection @@ -278,7 +274,7 @@ fn get_org_details(data: OrgIdData, headers: Headers, conn: DbConn) -> JsonResul } #[get("/organizations/<org_id>/users")] -fn get_org_users(org_id: String, headers: Headers, conn: DbConn) -> JsonResult { +fn get_org_users(org_id: String, headers: AdminHeaders, conn: DbConn) -> JsonResult { match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &conn) { Some(_) => (), None => err!("User isn't member of organization") @@ -408,13 +404,7 @@ fn confirm_invite(org_id: String, user_id: String, data: Json<Value>, headers: H } #[get("/organizations/<org_id>/users/<user_id>")] -fn get_user(org_id: String, user_id: String, headers: Headers, conn: DbConn) -> JsonResult { - let current_user = match UserOrganization::find_by_user_and_org( - &headers.user.uuid, &org_id, &conn) { - Some(user) => user, - None => err!("The current user isn't member of the organization") - }; - +fn get_user(org_id: String, user_id: String, headers: AdminHeaders, conn: DbConn) -> JsonResult { let user = match UserOrganization::find_by_uuid(&user_id, &conn) { Some(user) => user, None => err!("The specified user isn't member of the organization") diff --git a/src/auth.rs b/src/auth.rs @@ -94,7 +94,7 @@ use rocket::Outcome; use rocket::request::{self, Request, FromRequest}; use db::DbConn; -use db::models::{User, Device}; +use db::models::{User, UserOrganization, UserOrgType, Device}; pub struct Headers { pub host: String, @@ -155,4 +155,104 @@ impl<'a, 'r> FromRequest<'a, 'r> for Headers { Outcome::Success(Headers { host, device, user }) } +} + +pub struct OrgHeaders { + pub host: String, + pub device: Device, + pub user: User, + pub org_user_type: i32, +} + +impl<'a, 'r> FromRequest<'a, 'r> for OrgHeaders { + type Error = &'static str; + + fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { + match request.guard::<Headers>() { + Outcome::Forward(f) => Outcome::Forward(f), + Outcome::Failure(f) => Outcome::Failure(f), + Outcome::Success(headers) => { + // org_id is expected to be the first dynamic param + match request.get_param::<String>(0) { + Err(_) => err_handler!("Error getting the organization id"), + Ok(org_id) => { + let conn = match request.guard::<DbConn>() { + Outcome::Success(conn) => conn, + _ => err_handler!("Error getting DB") + }; + + let org_user = match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &conn) { + Some(user) => user, + None => err_handler!("The current user isn't member of the organization") + }; + + Outcome::Success(Self{ + host: headers.host, + device: headers.device, + user: headers.user, + org_user_type: org_user.type_, + }) + } + } + } + } + } +} + +pub struct AdminHeaders { + pub host: String, + pub device: Device, + pub user: User, + pub org_user_type: i32, +} + +impl<'a, 'r> FromRequest<'a, 'r> for AdminHeaders { + type Error = &'static str; + + fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { + match request.guard::<OrgHeaders>() { + Outcome::Forward(f) => Outcome::Forward(f), + Outcome::Failure(f) => Outcome::Failure(f), + Outcome::Success(headers) => { + if headers.org_user_type > UserOrgType::Admin as i32 { + err_handler!("You need to be Admin or Owner to call this endpoint") + } else { + Outcome::Success(Self{ + host: headers.host, + device: headers.device, + user: headers.user, + org_user_type: headers.org_user_type, + }) + } + } + } + } +} + +pub struct OwnerHeaders { + pub host: String, + pub device: Device, + pub user: User, +} + +impl<'a, 'r> FromRequest<'a, 'r> for OwnerHeaders { + type Error = &'static str; + + fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { + match request.guard::<OrgHeaders>() { + Outcome::Forward(f) => Outcome::Forward(f), + Outcome::Failure(f) => Outcome::Failure(f), + Outcome::Success(headers) => { + if headers.org_user_type > UserOrgType::Owner as i32 { + err_handler!("You need to be Owner to call this endpoint") + } else { + Outcome::Success(Self{ + host: headers.host, + device: headers.device, + user: headers.user, + }) + } + } + } + } } \ No newline at end of file