Files
AstralRinth/src/database/models/oauth_client_authorization_item.rs
Jackson Kruger 6cfd4637db 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
2023-10-30 09:14:38 -07:00

127 lines
3.4 KiB
Rust

use chrono::{DateTime, Utc};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use crate::models::pats::Scopes;
use super::{DatabaseError, OAuthClientAuthorizationId, OAuthClientId, UserId};
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct OAuthClientAuthorization {
pub id: OAuthClientAuthorizationId,
pub client_id: OAuthClientId,
pub user_id: UserId,
pub scopes: Scopes,
pub created: DateTime<Utc>,
}
struct AuthorizationQueryResult {
id: i64,
client_id: i64,
user_id: i64,
scopes: i64,
created: DateTime<Utc>,
}
impl From<AuthorizationQueryResult> for OAuthClientAuthorization {
fn from(value: AuthorizationQueryResult) -> Self {
OAuthClientAuthorization {
id: OAuthClientAuthorizationId(value.id),
client_id: OAuthClientId(value.client_id),
user_id: UserId(value.user_id),
scopes: Scopes::from_postgres(value.scopes),
created: value.created,
}
}
}
impl OAuthClientAuthorization {
pub async fn get(
client_id: OAuthClientId,
user_id: UserId,
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Option<OAuthClientAuthorization>, DatabaseError> {
let value = sqlx::query_as!(
AuthorizationQueryResult,
"
SELECT id, client_id, user_id, scopes, created
FROM oauth_client_authorizations
WHERE client_id=$1 AND user_id=$2
",
client_id.0,
user_id.0,
)
.fetch_optional(exec)
.await?;
Ok(value.map(|r| r.into()))
}
pub async fn get_all_for_user(
user_id: UserId,
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Vec<OAuthClientAuthorization>, DatabaseError> {
let results = sqlx::query_as!(
AuthorizationQueryResult,
"
SELECT id, client_id, user_id, scopes, created
FROM oauth_client_authorizations
WHERE user_id=$1
",
user_id.0
)
.fetch_all(exec)
.await?;
Ok(results.into_iter().map(|r| r.into()).collect_vec())
}
pub async fn upsert(
id: OAuthClientAuthorizationId,
client_id: OAuthClientId,
user_id: UserId,
scopes: Scopes,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> Result<(), DatabaseError> {
sqlx::query!(
"
INSERT INTO oauth_client_authorizations (
id, client_id, user_id, scopes
)
VALUES (
$1, $2, $3, $4
)
ON CONFLICT (id)
DO UPDATE SET scopes = EXCLUDED.scopes
",
id.0,
client_id.0,
user_id.0,
scopes.bits() as i64,
)
.execute(&mut **transaction)
.await?;
Ok(())
}
pub async fn remove(
client_id: OAuthClientId,
user_id: UserId,
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
) -> Result<(), DatabaseError> {
sqlx::query!(
"
DELETE FROM oauth_client_authorizations
WHERE client_id=$1 AND user_id=$2
",
client_id.0,
user_id.0
)
.execute(exec)
.await?;
Ok(())
}
}