Skip to content

Commit

Permalink
feat: add token introspection
Browse files Browse the repository at this point in the history
  • Loading branch information
emmanuelgautier committed Apr 2, 2024
1 parent a1a61fe commit 96f7110
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 8 deletions.
3 changes: 2 additions & 1 deletion baffao-proxy/config/example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ client_id = "client_id"
client_secret = "client_secret"
authorization_redirect_uri = "http://127.0.0.1:3000/oauth/callback"
authorization_endpoint = "http://127.0.0.1:4444/oauth2/auth"
token_endpoint = "http://127.0.0.1/oauth2/token"
token_endpoint = "http://127.0.0.1:3000/oauth2/token"
introspection_endpoint = "http://127.0.0.1:3000/oauth2/introspect"
redirect_uri = "http://127.0.0.1:3000/"
1 change: 1 addition & 0 deletions baffao-proxy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ async fn main() {
let app = Router::new()
.route("/oauth/authorize", get(oauth::authorize))
.route("/oauth/callback", get(oauth::callback))
.route("/oauth/introspect", get(oauth::introspect))
.route("/session", get(session::get_session))
.fallback(any(proxy::handler))
.layer(
Expand Down
7 changes: 7 additions & 0 deletions baffao-proxy/src/oauth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,10 @@ pub async fn callback(

(updated_jar, Redirect::temporary(&url.to_string()))
}

pub async fn introspect(
jar: CookieJar,
State(handler): State<OAuthHttpHandler>,
) -> impl IntoResponse {
handler.introspect(jar).await;
}
13 changes: 13 additions & 0 deletions baffao/src/handlers/introspect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use axum_extra::extract::CookieJar;
use reqwest::StatusCode;

use crate::oauth::{IntrospectionTokenResponse, OAuthHttpHandler};

pub async fn oauth2_introspect(
handler: OAuthHttpHandler,
jar: CookieJar,
) -> (CookieJar, StatusCode, Option<IntrospectionTokenResponse>) {

Check warning on line 9 in baffao/src/handlers/introspect.rs

View workflow job for this annotation

GitHub Actions / cargo fmt & test

Diff in /home/runner/work/baffao/baffao/baffao/src/handlers/introspect.rs
let (updated_jar, response) = handler.introspect(jar).await;

(updated_jar, response.to_owned().map_or_else(|| StatusCode::UNAUTHORIZED, |_| StatusCode::OK), response)
}
2 changes: 2 additions & 0 deletions baffao/src/handlers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
pub use authorize::{oauth2_authorize, AuthorizationQuery};
pub use callback::{oauth2_callback, AuthorizationCallbackQuery};
pub use get_session::get_session_from_cookie;
pub use introspect::oauth2_introspect;
pub use proxy::proxy;

mod authorize;
mod callback;
mod get_session;
mod introspect;
mod proxy;
28 changes: 23 additions & 5 deletions baffao/src/oauth/client.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use anyhow::{Context, Error};

Check warning on line 1 in baffao/src/oauth/client.rs

View workflow job for this annotation

GitHub Actions / cargo fmt & test

Diff in /home/runner/work/baffao/baffao/baffao/src/oauth/client.rs
use oauth2::{
basic::BasicClient, reqwest::async_http_client, AuthType, AuthUrl, AuthorizationCode, ClientId,
ClientSecret, CsrfToken, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope,
TokenUrl,
basic::BasicClient, reqwest::async_http_client, AccessToken as OAuthAccessToken, AuthType, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, IntrospectionUrl, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope, TokenUrl
};
use reqwest::Url;

use super::{AccessToken, OAuthConfig};
use super::{AccessToken, IntrospectionTokenResponse, OAuthConfig};

pub struct OAuthClient {
config: OAuthConfig,
Expand All @@ -31,7 +29,7 @@ impl OAuthClient {
let token_endpoint =
TokenUrl::new(config.token_endpoint.clone()).context("Failed to parse token url")?;

let client = BasicClient::new(
let mut client = BasicClient::new(
ClientId::new(config.client_id.clone()),
Some(ClientSecret::new(config.client_secret.clone())),
auth_url,
Expand All @@ -40,6 +38,12 @@ impl OAuthClient {
.set_auth_type(AuthType::RequestBody)
.set_redirect_uri(redirect_uri);

if let Some(introspection_endpoint) = &config.introspection_endpoint {
let introspection_endpoint = IntrospectionUrl::new(introspection_endpoint.clone())
.context("Failed to parse introspection url")?;
client = client.set_introspection_uri(introspection_endpoint);
}

Ok(Self { config, client })
}

Expand Down Expand Up @@ -105,4 +109,18 @@ impl OAuthClient {

Ok(response.unwrap())
}

pub async fn introspect_token(

Check warning on line 113 in baffao/src/oauth/client.rs

View workflow job for this annotation

GitHub Actions / cargo fmt & test

Diff in /home/runner/work/baffao/baffao/baffao/src/oauth/client.rs
&self,
token: String,
) -> Result<IntrospectionTokenResponse, Error>
{
let response = self
.client
.introspect(&OAuthAccessToken::new(token))?
.request_async(async_http_client)
.await?;

Ok(response)
}
}
12 changes: 11 additions & 1 deletion baffao/src/oauth/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use axum_extra::extract::CookieJar;
use chrono::{Duration, Utc};
use oauth2::TokenResponse;

use super::OAuthConfig;
use super::{IntrospectionTokenResponse, OAuthConfig};
use crate::cookies::new_cookie;
use crate::session::{update_session, Session};
use crate::{oauth::OAuthClient, settings::CookiesConfig};
Expand Down Expand Up @@ -130,4 +130,14 @@ impl OAuthHttpHandler {
cookies_config: self.cookies_config.clone(),
}

Check warning on line 131 in baffao/src/oauth/http.rs

View workflow job for this annotation

GitHub Actions / cargo fmt & test

Diff in /home/runner/work/baffao/baffao/baffao/src/oauth/http.rs
}

pub async fn introspect(&self, jar: CookieJar) -> (CookieJar, Option<IntrospectionTokenResponse>) {
let (updated_jar, access_token) = self.get_or_refresh_token(jar).await.unwrap();
if access_token.is_none() {
return (updated_jar, None)
}

let result = self.client.introspect_token(access_token.unwrap().to_string()).await.unwrap();
(updated_jar, Some(result))
}
}
4 changes: 3 additions & 1 deletion baffao/src/oauth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub use http::OAuthHttpHandler;
mod client;

Check warning on line 4 in baffao/src/oauth/mod.rs

View workflow job for this annotation

GitHub Actions / cargo fmt & test

Diff in /home/runner/work/baffao/baffao/baffao/src/oauth/mod.rs
mod http;

use oauth2::{basic::BasicTokenType, EmptyExtraTokenFields, StandardTokenResponse};
use oauth2::{basic::BasicTokenType, EmptyExtraTokenFields, StandardTokenIntrospectionResponse, StandardTokenResponse};

use serde::Deserialize;

Expand All @@ -22,8 +22,10 @@ pub struct OAuthConfig {
pub authorization_redirect_uri: String,
pub authorization_endpoint: String,
pub token_endpoint: String,
pub introspection_endpoint: Option<String>,
pub redirect_uri: Option<String>,
pub default_scopes: Option<Vec<String>>,
}

Check warning on line 28 in baffao/src/oauth/mod.rs

View workflow job for this annotation

GitHub Actions / cargo fmt & test

Diff in /home/runner/work/baffao/baffao/baffao/src/oauth/mod.rs

pub type AccessToken = StandardTokenResponse<EmptyExtraTokenFields, BasicTokenType>;
pub type IntrospectionTokenResponse = StandardTokenIntrospectionResponse<EmptyExtraTokenFields, BasicTokenType>;

0 comments on commit 96f7110

Please sign in to comment.