Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
573 changes: 568 additions & 5 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion baffao-proxy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use axum::{
routing::{any, get},
Router,
};
use baffao::oauth::OAuthHttpHandler;
use baffao::openidconnect::OAuthHttpHandler;
use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};
use std::time::Duration;
use tokio::signal;
Expand Down
2 changes: 1 addition & 1 deletion baffao-proxy/src/oauth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use axum::{
use axum_extra::extract::CookieJar;
use baffao::{
handlers::{oauth2_authorize, oauth2_callback, AuthorizationCallbackQuery, AuthorizationQuery},
oauth::OAuthHttpHandler,
openidconnect::OAuthHttpHandler,
};

// TODO: use signed cookies
Expand Down
2 changes: 1 addition & 1 deletion baffao-proxy/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use axum::{
response::IntoResponse,
};
use axum_extra::extract::CookieJar;
use baffao::{handlers::proxy, oauth::OAuthHttpHandler};
use baffao::{handlers::proxy, openidconnect::OAuthHttpHandler};

use crate::settings::Settings;
use crate::state::HttpClient;
Expand Down
2 changes: 1 addition & 1 deletion baffao-proxy/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use serde::Deserialize;
use std::env;

use baffao::{
oauth::OAuthConfig,
openidconnect::OAuthConfig,
settings::{JwtConfig, ServerConfig},
};

Expand Down
2 changes: 1 addition & 1 deletion baffao-proxy/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use axum::{body::Body, extract::FromRef};
use baffao::oauth::OAuthHttpHandler;
use baffao::openidconnect::OAuthHttpHandler;
use hyper_util::client::legacy::connect::HttpConnector;

use crate::settings::Settings;
Expand Down
2 changes: 1 addition & 1 deletion baffao/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ cookie = "0.18.0"
hex = "0.4.3"
http = "1.1.0"
jsonwebtoken = "9.2.0"
oauth2 = "4.4.2"
openidconnect = "3.5.0"
reqwest = "0.11.24"
ring = "0.17.8"
serde = "1.0.197"
Expand Down
2 changes: 1 addition & 1 deletion baffao/src/handlers/authorize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use axum_extra::extract::CookieJar;
use reqwest::StatusCode;
use serde::Deserialize;

use crate::oauth::OAuthHttpHandler;
use crate::openidconnect::OAuthHttpHandler;

#[derive(Deserialize)]
pub struct AuthorizationQuery {
Expand Down
2 changes: 1 addition & 1 deletion baffao/src/handlers/callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::Deserialize;

use crate::{
error::build_error_redirect_url,
oauth::OAuthHttpHandler,
openidconnect::OAuthHttpHandler,
settings::{CookiesConfig, ServerConfig},
};

Expand Down
2 changes: 1 addition & 1 deletion baffao/src/handlers/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use anyhow::{Error, Ok};
use axum_extra::extract::CookieJar;
use http::HeaderMap;

use crate::oauth::OAuthHttpHandler;
use crate::openidconnect::OAuthHttpHandler;

pub async fn proxy(
handler: OAuthHttpHandler,
Expand Down
2 changes: 1 addition & 1 deletion baffao/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod handlers;
pub mod oauth;
pub mod openidconnect;
pub mod session;

pub mod cookies;
Expand Down
59 changes: 42 additions & 17 deletions baffao/src/oauth/client.rs → baffao/src/openidconnect/client.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,73 @@
use anyhow::{Context, Error};
use oauth2::{
basic::BasicClient, reqwest::async_http_client, AuthType, AuthUrl, AuthorizationCode, ClientId,
ClientSecret, CsrfToken, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope,
TokenUrl,
use anyhow::Error;
use openidconnect::{
core::CoreClient, reqwest::async_http_client, AuthType, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, IssuerUrl, JsonWebKeySet, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope, TokenUrl, UserInfoUrl
};
use reqwest::Url;

use super::{AccessToken, OAuthConfig};

pub struct OAuthClient {
pub struct OpenIDConnectClient {
config: OAuthConfig,
client: BasicClient,
client: CoreClient,
}

impl Clone for OAuthClient {
impl Clone for OpenIDConnectClient {
fn clone(&self) -> Self {
OAuthClient {
OpenIDConnectClient {
config: self.config.clone(),
client: self.client.clone(),
}
}
}

impl OAuthClient {
impl OpenIDConnectClient {
pub fn new(config: OAuthConfig) -> Result<Self, Error> {
let redirect_uri = RedirectUrl::new(config.authorization_redirect_uri.clone())
.context("Failed to parse redirect uri")?;
let auth_url = AuthUrl::new(config.authorization_endpoint.clone())
.context("Failed to parse authorization url")?;
let redirect_uri = RedirectUrl::new(config.authorization_redirect_uri)?;
let auth_url = AuthUrl::new(config.authorization_endpoint)?;
let issuer = IssuerUrl::new(config.issuer)?;
let token_endpoint =
TokenUrl::new(config.token_endpoint.clone()).context("Failed to parse token url")?;
TokenUrl::new(config.token_endpoint)?;
let user_info_endpoint = if config.userinfo_endpoint.is_some() {
Some(UserInfoUrl::new(config.userinfo_endpoint.unwrap())?)
} else {
None
};
if (config.jwks_uri.is_some() && config.jwks_uri.as_ref().unwrap().is_empty())
|| (config.default_scopes.is_some() && config.default_scopes.as_ref().unwrap().is_empty())
{
return Err(Error::msg("Invalid configuration"));
}
let jwks = if config.jwks_uri.is_some() {
Some(JsonWebKeySet::fetch(config.jwks_uri.unwrap())?)
} else {
None
};

let client = BasicClient::new(
let client = CoreClient::new(
ClientId::new(config.client_id.clone()),
Some(ClientSecret::new(config.client_secret.clone())),
Some(ClientSecret::new(config.client_secret)),
issuer,
auth_url,
Some(token_endpoint),
user_info_endpoint,
jwks,
)
.set_auth_type(AuthType::RequestBody)
.set_redirect_uri(redirect_uri);

Ok(Self { config, client })
}

pub fn from_provider_metadata(&self) -> Result<Self, Error> {
CoreClient::from_provider_metadata(
provider_metadata,
ClientId::new(config.client_id.clone()),
Some(ClientSecret::new(config.client_secret)),
);

Ok(Self { config, client })
}

pub fn build_authorization_endpoint(
&self,
scope: Option<Vec<String>>,
Expand Down
16 changes: 12 additions & 4 deletions baffao/src/oauth/http.rs → baffao/src/openidconnect/http.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
use anyhow::{Error, Ok};
use axum_extra::extract::CookieJar;
use chrono::{Duration, Utc};
use oauth2::TokenResponse;

use super::OAuthConfig;
use crate::cookies::new_cookie;
use crate::session::{update_session, Session};
use crate::{oauth::OAuthClient, settings::CookiesConfig};
use crate::{openidconnect::OAuthClient, settings::CookiesConfig};

#[derive(Clone)]
pub struct OAuthHttpHandler {
pub struct OpenIDConnectHttpHandler {
client: OAuthClient,
cookies_config: CookiesConfig,
}

impl OAuthHttpHandler {
impl OpenIDConnectHttpHandler {
pub fn new(oauth_config: OAuthConfig, cookies_config: CookiesConfig) -> Result<Self, Error> {
let client = OAuthClient::new(oauth_config)?;

Expand Down Expand Up @@ -108,6 +107,15 @@ impl OAuthHttpHandler {
updated_jar = updated_jar.remove(self.cookies_config.refresh_token.to_owned().name);
}

if token_result.id_token().is_some() {
updated_jar = updated_jar.add(new_cookie(
self.cookies_config.id_token.to_owned(),
token_result.id_token().unwrap().secret().to_string(),
));
} else {
updated_jar = updated_jar.remove(self.cookies_config.id_token.to_owned().name);
}

let now = Utc::now();
let expires_in = token_result.expires_in().map(|duration| {
now.checked_add_signed(Duration::from_std(duration).unwrap())
Expand Down
5 changes: 4 additions & 1 deletion baffao/src/oauth/mod.rs → baffao/src/openidconnect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub use http::OAuthHttpHandler;
mod client;
mod http;

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

use serde::Deserialize;

Expand All @@ -19,10 +19,13 @@ use serde::Deserialize;
pub struct OAuthConfig {
pub client_id: String,
pub client_secret: String,
pub issuer: String,
pub authorization_redirect_uri: String,
pub authorization_endpoint: String,
pub token_endpoint: String,
pub userinfo_endpoint: Option<String>,
pub redirect_uri: Option<String>,
pub jwks_uri: Option<String>,
pub default_scopes: Option<Vec<String>>,
}

Expand Down