OAuth 2.0 Authorization Server [MOD-559] (#733)

* WIP end-of-day push

* Authorize endpoint, accept endpoints, DB stuff for oauth clients, their redirects, and client authorizations

* OAuth Client create route

* Get user clients

* Client delete

* Edit oauth client

* Include redirects in edit client route

* Database stuff for tokens

* Reorg oauth stuff out of auth/flows and into its own module

* Impl OAuth get access token endpoint

* Accept oauth access tokens as auth and update through AuthQueue

* User OAuth authorization management routes

* Forgot to actually add the routes lol

* Bit o cleanup

* Happy path test for OAuth and minor fixes for things it found

* Add dummy data oauth client (and detect/handle dummy data version changes)

* More tests

* Another test

* More tests and reject endpoint

* Test oauth client and authorization management routes

* cargo sqlx prepare

* dead code warning

* Auto clippy fixes

* Uri refactoring

* minor name improvement

* Don't compile-time check the test sqlx queries

* Trying to fix db concurrency problem to get tests to pass

* Try fix from test PR

* Fixes for updated sqlx

* Prevent restricted scopes from being requested or issued

* Get OAuth client(s)

* Remove joined oauth client info from authorization returns

* Add default conversion to OAuthError::error so we can use ?

* Rework routes

* Consolidate scopes into SESSION_ACCESS

* Cargo sqlx prepare

* Parse to OAuthClientId automatically through serde and actix

* Cargo clippy

* Remove validation requiring 1 redirect URI on oauth client creation

* Use serde(flatten) on OAuthClientCreationResult
This commit is contained in:
Jackson Kruger
2023-10-30 11:14:38 -05:00
committed by GitHub
parent 8803e11945
commit 6cfd4637db
54 changed files with 3658 additions and 135 deletions

View File

@@ -8,6 +8,25 @@ use crate::routes::ApiError;
use actix_web::web;
use sqlx::PgPool;
pub trait ValidateAuthorized {
fn validate_authorized(&self, user_option: Option<&User>) -> Result<(), ApiError>;
}
pub trait ValidateAllAuthorized {
fn validate_all_authorized(self, user_option: Option<&User>) -> Result<(), ApiError>;
}
impl<'a, T, A> ValidateAllAuthorized for T
where
T: IntoIterator<Item = &'a A>,
A: ValidateAuthorized + 'a,
{
fn validate_all_authorized(self, user_option: Option<&User>) -> Result<(), ApiError> {
self.into_iter()
.try_for_each(|c| c.validate_authorized(user_option))
}
}
pub async fn is_authorized(
project_data: &Project,
user_option: &Option<User>,
@@ -156,6 +175,23 @@ pub async fn is_authorized_version(
Ok(authorized)
}
impl ValidateAuthorized for crate::database::models::OAuthClient {
fn validate_authorized(&self, user_option: Option<&User>) -> Result<(), ApiError> {
if let Some(user) = user_option {
if user.role.is_mod() || user.id == self.created_by.into() {
return Ok(());
} else {
return Err(crate::routes::ApiError::CustomAuthentication(
"You don't have sufficient permissions to interact with this OAuth application"
.to_string(),
));
}
}
Ok(())
}
}
pub async fn filter_authorized_versions(
versions: Vec<QueryVersion>,
user_option: &Option<User>,