From 455fa062ef50003485e895298112600dec7f7231 Mon Sep 17 00:00:00 2001 From: mrw1593 Date: Sun, 18 Jun 2023 15:34:28 -0400 Subject: Implement the password grant --- Cargo.lock | 10 --------- Cargo.toml | 1 - src/api/oauth.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1fa4db3..bbb5065 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1688,7 +1688,6 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "serde_variant", "sha2", "sqlx", "tera", @@ -1808,15 +1807,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a8ec0b2fd0506290348d9699c0e3eb2e3e8c0498b5a9a6158b3bd4d6970076" -dependencies = [ - "serde", -] - [[package]] name = "sha1" version = "0.10.5" diff --git a/Cargo.toml b/Cargo.toml index eae42e1..28841be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,4 +33,3 @@ sqlx = { version = "0.6", features = [ "runtime-actix-rustls", "mysql", "uuid", log = "0.4" chrono = { version = "0.4", features = ["serde"] } hex = "0.4" -serde_variant = "0.1" diff --git a/src/api/oauth.rs b/src/api/oauth.rs index 48c3210..f25bf41 100644 --- a/src/api/oauth.rs +++ b/src/api/oauth.rs @@ -44,11 +44,20 @@ struct AuthorizeCredentials { } #[derive(Clone, Serialize)] -struct CodeResponse { +struct AuthCodeResponse { code: Box, state: Option>, } +#[derive(Clone, Serialize)] +struct AuthTokenResponse { + access_token: Box, + token_type: &'static str, + expires_in: i64, + scope: Box, + state: Option>, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] #[serde(rename_all = "camelCase")] enum AuthorizeErrorType { @@ -61,13 +70,14 @@ enum AuthorizeErrorType { TemporarilyUnavailable, } -#[derive(Debug, Clone, Error)] +#[derive(Debug, Clone, Error, Serialize)] #[error("{error_description}")] struct AuthorizeError { error: AuthorizeErrorType, error_description: Box, // TODO error uri state: Option>, + #[serde(skip)] redirect_uri: Url, } @@ -86,15 +96,10 @@ impl AuthorizeError { impl ResponseError for AuthorizeError { fn error_response(&self) -> HttpResponse { - let error = serde_variant::to_variant_name(&self.error).unwrap_or_default(); + let query = Some(serde_urlencoded::to_string(self).unwrap()); + let query = query.as_deref(); let mut url = self.redirect_uri.clone(); - url.query_pairs_mut() - .append_pair("error", error) - .append_pair("error_description", &self.error_description); - - if let Some(state) = &self.state { - url.query_pairs_mut().append_pair("state", &state); - } + url.set_query(query); HttpResponse::Found() .insert_header((header::LOCATION, url.as_str())) @@ -109,6 +114,7 @@ async fn authorize( credentials: web::Json, ) -> HttpResponse { // TODO use sessions to verify that the request was previously validated + // TODO handle internal server error let db = db.get_ref(); let Some(client_id) = db::get_client_id_by_alias(db, &req.client_id).await.unwrap() else { todo!("client not found") @@ -117,7 +123,7 @@ async fn authorize( let state = req.state.clone(); // get redirect uri - let redirect_uri = if let Some(redirect_uri) = &req.redirect_uri { + let mut redirect_uri = if let Some(redirect_uri) = &req.redirect_uri { redirect_uri.clone() } else { let redirect_uris = db::get_client_redirect_uris(db, client_id).await.unwrap(); @@ -157,11 +163,43 @@ async fn authorize( .await .unwrap(); let code = code.to_jwt().unwrap(); - let response = CodeResponse { code, state }; - HttpResponse::Ok().json(response) + let response = AuthCodeResponse { code, state }; + let query = Some(serde_urlencoded::to_string(response).unwrap()); + let query = query.as_deref(); + redirect_uri.set_query(query); + + HttpResponse::Found() + .append_header((header::LOCATION, redirect_uri.as_str())) + .finish() + } + ResponseType::Token => { + // create access token + let duration = Duration::hours(1); + let access_token = + jwt::Claims::access_token(db, None, self_id, client_id, duration, &scope) + .await + .unwrap(); + + let access_token = access_token.to_jwt().unwrap(); + let expires_in = duration.num_seconds(); + let token_type = "bearer"; + let response = AuthTokenResponse { + access_token, + expires_in, + token_type, + scope, + state, + }; + + let fragment = Some(serde_urlencoded::to_string(response).unwrap()); + let fragment = fragment.as_deref(); + redirect_uri.set_fragment(fragment); + + HttpResponse::Found() + .append_header((header::LOCATION, redirect_uri.as_str())) + .finish() } - ResponseType::Token => todo!(), _ => todo!("unsupported response type"), } } -- cgit v1.2.3