-
Notifications
You must be signed in to change notification settings - Fork 164
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Simplify security.rs and authorization logic (#674)
This PR refactors `security.rs` and our auth* related axum extractors. ## Motivation * Cut down on lines-of-code * Make permission/authorization parsing a bit more intuitive for axum handlers * Better leverage the type system to restrict axum handlers only to the permission-level information they need. ## Solution Some specifics * Many of our extractors had redundant information, or largely unused fields. This PR removes them * The `Permissions` struct has been simplified a bit, namely by moving things into an enum (as opposed to using the `type_` enum just as a tag. * Removed the axum extractor for `Permissions`. We often chain authorization logic on top of the `Permissions`. However, the axum extractor for `Permissions` only authenticates requests, it doesn't authorize them. * Fixes a discrepancy between `list_event_types` and `get_event_type`. `list_event_types` was not checking for Organization privileges like `get_event_types` was. * `AuthenticatedOrganization`, `AuthenticatedApp`, etc, were also simplified a bit, and moved into a separate `permissions.rs` module.
- Loading branch information
Showing
13 changed files
with
206 additions
and
280 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use axum::{ | ||
async_trait, | ||
extract::{FromRequest, Path, RequestParts}, | ||
Extension, | ||
}; | ||
use sea_orm::DatabaseConnection; | ||
|
||
use crate::{ | ||
ctx, | ||
db::models::application, | ||
error::{Error, HttpError, Result}, | ||
}; | ||
|
||
use super::{ | ||
security::{permissions_from_bearer, AccessLevel}, | ||
types::{ApplicationIdOrUid, OrganizationId}, | ||
}; | ||
|
||
pub struct Organization { | ||
pub org_id: OrganizationId, | ||
} | ||
|
||
#[async_trait] | ||
impl<B> FromRequest<B> for Organization | ||
where | ||
B: Send, | ||
{ | ||
type Rejection = Error; | ||
|
||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self> { | ||
let permissions = permissions_from_bearer(req).await?; | ||
|
||
let org_id = match permissions.access_level { | ||
AccessLevel::Organization(org_id) => org_id, | ||
_ => return Err(HttpError::permission_denied(None, None).into()), | ||
}; | ||
|
||
Ok(Self { org_id }) | ||
} | ||
} | ||
|
||
pub struct Application { | ||
pub app: application::Model, | ||
} | ||
|
||
#[async_trait] | ||
impl<B> FromRequest<B> for Application | ||
where | ||
B: Send, | ||
{ | ||
type Rejection = Error; | ||
|
||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self> { | ||
let permissions = permissions_from_bearer(req).await?; | ||
|
||
let Path(ApplicationPathParams { app_id }) = | ||
ctx!(Path::<ApplicationPathParams>::from_request(req).await)?; | ||
let Extension(ref db) = ctx!(Extension::<DatabaseConnection>::from_request(req).await)?; | ||
let app = ctx!( | ||
application::Entity::secure_find_by_id_or_uid(permissions.org_id(), app_id.to_owned(),) | ||
.one(db) | ||
.await | ||
)? | ||
.ok_or_else(|| HttpError::not_found(None, None))?; | ||
|
||
if let Some(permitted_app_id) = permissions.app_id() { | ||
if permitted_app_id != app.id { | ||
return Err(HttpError::not_found(None, None).into()); | ||
} | ||
} | ||
|
||
Ok(Self { app }) | ||
} | ||
} | ||
|
||
// Organization level privileges, with the requested application | ||
pub struct OrganizationWithApplication { | ||
pub app: application::Model, | ||
} | ||
|
||
#[async_trait] | ||
impl<B> FromRequest<B> for OrganizationWithApplication | ||
where | ||
B: Send, | ||
{ | ||
type Rejection = Error; | ||
|
||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self> { | ||
let Organization { org_id } = ctx!(Organization::from_request(req).await)?; | ||
|
||
let Path(ApplicationPathParams { app_id }) = | ||
ctx!(Path::<ApplicationPathParams>::from_request(req).await)?; | ||
let Extension(ref db) = ctx!(Extension::<DatabaseConnection>::from_request(req).await)?; | ||
let app = ctx!( | ||
application::Entity::secure_find_by_id_or_uid(org_id, app_id.to_owned(),) | ||
.one(db) | ||
.await | ||
)? | ||
.ok_or_else(|| HttpError::not_found(None, None))?; | ||
Ok(OrganizationWithApplication { app }) | ||
} | ||
} | ||
|
||
#[derive(serde::Deserialize)] | ||
struct ApplicationPathParams { | ||
app_id: ApplicationIdOrUid, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.