From 904d0fc45eefa518dc7b51ae8eee6168797553ba Mon Sep 17 00:00:00 2001 From: ajuvercr Date: Sat, 12 Mar 2022 20:34:31 +0100 Subject: [PATCH 1/3] add introspect endpoint RFC 7662 --- Cargo.lock | 2 +- src/controllers/oauth_controller.rs | 30 +++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index a7ed0ca1..8ed284f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2829,7 +2829,7 @@ checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" [[package]] name = "zauth" -version = "1.2.1" +version = "1.3.0" dependencies = [ "askama", "askama_rocket", diff --git a/src/controllers/oauth_controller.rs b/src/controllers/oauth_controller.rs index efa34776..baecf833 100644 --- a/src/controllers/oauth_controller.rs +++ b/src/controllers/oauth_controller.rs @@ -316,3 +316,33 @@ pub async fn token( })) } } + +#[derive(Serialize, Debug)] +pub struct IntrospectResp { + active: bool, +} + +#[derive(FromForm, Debug)] +pub struct IntrospectFormData { + token: String, + token_type_hint: Option, +} + +#[post("/oauth/introspect", data = "
")] +pub async fn introspect( + auth: Option, + form: Form, + db: DbConn, +) -> Result> { + let auth = auth + .map(|auth| (auth.user, auth.password)) + .ok_or(ZauthError::from(OAuthError::InvalidRequest))?; + + Client::find_and_authenticate(auth.0.to_string(), &auth.1, &db).await?; + + let IntrospectFormData { token, .. } = form.into_inner(); + let maybe_session = Session::find_by_key(token, &db).await; + Ok(Json(IntrospectResp { + active: maybe_session.is_ok(), + })) +} diff --git a/src/lib.rs b/src/lib.rs index 6ce9448f..c50dbf44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,6 +101,7 @@ fn assemble(rocket: Rocket) -> Rocket { oauth_controller::grant_get, oauth_controller::grant_post, oauth_controller::token, + oauth_controller::introspect, pages_controller::home_page, sessions_controller::create_session, sessions_controller::new_session, From 5a75658f82e4db4ad2e1b02c7d2d14b8d861e554 Mon Sep 17 00:00:00 2001 From: ajuvercr Date: Sat, 12 Mar 2022 20:54:24 +0100 Subject: [PATCH 2/3] add test --- tests/oauth.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/tests/oauth.rs b/tests/oauth.rs index 6d77814d..2d71664f 100644 --- a/tests/oauth.rs +++ b/tests/oauth.rs @@ -170,6 +170,25 @@ async fn normal_flow() { assert_eq!(response.status(), Status::SeeOther); + let credentials = + base64::encode(&format!("{}:{}", client_id, client.secret)); + + let form_body = format!("token=1234"); + let req = http_client + .post("/oauth/introspect") + .header(ContentType::Form) + .header(Header::new( + "Authorization", + format!("Basic {}", credentials), + )) + .body(form_body); + + let response = req.dispatch().await; + assert_eq!(response.status(), Status::Ok); + let response_body = response.into_string().await.expect("response body"); + let data: Value = serde_json::from_str(&response_body).expect("response json values"); + assert_eq!(data["active"], false); + // 7a. Client requests access code while sending its credentials // trough HTTP Auth. let token_url = "/oauth/token"; @@ -178,9 +197,6 @@ async fn normal_flow() { authorization_code, redirect_uri ); - let credentials = - base64::encode(&format!("{}:{}", client_id, client.secret)); - let req = http_client .post(token_url) .header(ContentType::Form) @@ -256,6 +272,22 @@ async fn normal_flow() { assert_eq!(data["token_type"], "bearer"); let token = data["access_token"].as_str().expect("access token"); + let form_body = format!("token={}", token); + let req = http_client + .post("/oauth/introspect") + .header(ContentType::Form) + .header(Header::new( + "Authorization", + format!("Basic {}", credentials), + )) + .body(form_body); + + let response = req.dispatch().await; + assert_eq!(response.status(), Status::Ok); + let response_body = response.into_string().await.expect("response body"); + let data: Value = serde_json::from_str(&response_body).expect("response json values"); + assert_eq!(data["active"], true); + let response = http_client .get("/current_user") .header(Accept::JSON) @@ -276,6 +308,24 @@ async fn normal_flow() { assert!(data["id"].is_number()); assert_eq!(data["username"], user_username); + + http_client.post("/logout").dispatch().await; + + let form_body = format!("token=1234"); + let req = http_client + .post("/oauth/introspect") + .header(ContentType::Form) + .header(Header::new( + "Authorization", + format!("Basic {}", credentials), + )) + .body(form_body); + + let response = req.dispatch().await; + assert_eq!(response.status(), Status::Ok); + let response_body = response.into_string().await.expect("response body"); + let data: Value = serde_json::from_str(&response_body).expect("response json values"); + assert_eq!(data["active"], false); }) .await; } From 65aea1072b015c66e8dd295deb656eafb1382675 Mon Sep 17 00:00:00 2001 From: ajuvercr Date: Sat, 12 Mar 2022 20:55:47 +0100 Subject: [PATCH 3/3] fmt --- tests/oauth.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/oauth.rs b/tests/oauth.rs index 2d71664f..7a5c8072 100644 --- a/tests/oauth.rs +++ b/tests/oauth.rs @@ -185,8 +185,10 @@ async fn normal_flow() { let response = req.dispatch().await; assert_eq!(response.status(), Status::Ok); - let response_body = response.into_string().await.expect("response body"); - let data: Value = serde_json::from_str(&response_body).expect("response json values"); + let response_body = + response.into_string().await.expect("response body"); + let data: Value = + serde_json::from_str(&response_body).expect("response json values"); assert_eq!(data["active"], false); // 7a. Client requests access code while sending its credentials @@ -284,8 +286,10 @@ async fn normal_flow() { let response = req.dispatch().await; assert_eq!(response.status(), Status::Ok); - let response_body = response.into_string().await.expect("response body"); - let data: Value = serde_json::from_str(&response_body).expect("response json values"); + let response_body = + response.into_string().await.expect("response body"); + let data: Value = + serde_json::from_str(&response_body).expect("response json values"); assert_eq!(data["active"], true); let response = http_client @@ -323,8 +327,10 @@ async fn normal_flow() { let response = req.dispatch().await; assert_eq!(response.status(), Status::Ok); - let response_body = response.into_string().await.expect("response body"); - let data: Value = serde_json::from_str(&response_body).expect("response json values"); + let response_body = + response.into_string().await.expect("response body"); + let data: Value = + serde_json::from_str(&response_body).expect("response json values"); assert_eq!(data["active"], false); }) .await;