Rework browser sessions
This commit is contained in:
110
src/axum_lib.rs
110
src/axum_lib.rs
@@ -1,5 +1,4 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use async_redis_session::RedisSessionStore;
|
||||
use axum::{
|
||||
extract::{self, Extension, Form, Path, Query, TypedHeader},
|
||||
http::{
|
||||
@@ -22,7 +21,7 @@ use headers::{
|
||||
};
|
||||
use openidconnect::core::{
|
||||
CoreClientMetadata, CoreClientRegistrationResponse, CoreJsonWebKeySet, CoreProviderMetadata,
|
||||
CoreResponseType, CoreTokenResponse, CoreUserInfoClaims, CoreUserInfoJsonWebToken,
|
||||
CoreTokenResponse, CoreUserInfoClaims, CoreUserInfoJsonWebToken,
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
use rsa::{
|
||||
@@ -38,7 +37,6 @@ use tracing::info;
|
||||
|
||||
use super::config;
|
||||
use super::oidc::{self, CustomError};
|
||||
use super::session::*;
|
||||
use ::siwe_oidc::db::*;
|
||||
|
||||
impl IntoResponse for CustomError {
|
||||
@@ -82,14 +80,6 @@ async fn provider_metadata(
|
||||
Ok(oidc::metadata(config.base_url)?.into())
|
||||
}
|
||||
|
||||
// TODO should check Authorization header
|
||||
// Actually, client secret can be
|
||||
// 1. in the POST (currently supported) [x]
|
||||
// 2. Authorization header [x]
|
||||
// 3. JWT [ ]
|
||||
// 4. signed JWT [ ]
|
||||
// according to Keycloak
|
||||
|
||||
async fn token(
|
||||
Form(form): Form<oidc::TokenForm>,
|
||||
bearer: Option<TypedHeader<Authorization<Bearer>>>,
|
||||
@@ -116,43 +106,16 @@ async fn token(
|
||||
Ok(token_response.into())
|
||||
}
|
||||
|
||||
// TODO handle `registration` parameter
|
||||
async fn authorize(
|
||||
session: UserSessionFromSession,
|
||||
Query(params): Query<oidc::AuthorizeParams>,
|
||||
Extension(redis_client): Extension<RedisClient>,
|
||||
) -> Result<(HeaderMap, Redirect), CustomError> {
|
||||
let (nonce, headers) = match session {
|
||||
UserSessionFromSession::Found(nonce) => (nonce, HeaderMap::new()),
|
||||
UserSessionFromSession::Invalid(cookie) => {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(header::SET_COOKIE, cookie);
|
||||
return Ok((
|
||||
headers,
|
||||
Redirect::to(
|
||||
format!(
|
||||
"/authorize?client_id={}&redirect_uri={}&scope={}&response_type={}&state={}&client_id={}{}",
|
||||
¶ms.client_id,
|
||||
¶ms.redirect_uri.to_string(),
|
||||
¶ms.scope.to_string(),
|
||||
¶ms.response_type.unwrap_or(CoreResponseType::Code).as_ref(),
|
||||
¶ms.state.unwrap_or_default(),
|
||||
¶ms.client_id,
|
||||
¶ms.nonce.map(|n| format!("&nonce={}", n.secret())).unwrap_or_default()
|
||||
)
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("Could not parse URI: {}", e))?,
|
||||
),
|
||||
));
|
||||
}
|
||||
UserSessionFromSession::Created { header, nonce } => {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(header::SET_COOKIE, header);
|
||||
(nonce, headers)
|
||||
}
|
||||
};
|
||||
|
||||
let url = oidc::authorize(params, nonce, &redis_client).await?;
|
||||
let (url, session_cookie) = oidc::authorize(params, &redis_client).await?;
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(
|
||||
header::SET_COOKIE,
|
||||
session_cookie.to_string().parse().unwrap(),
|
||||
);
|
||||
Ok((
|
||||
headers,
|
||||
Redirect::to(
|
||||
@@ -164,58 +127,16 @@ async fn authorize(
|
||||
}
|
||||
|
||||
async fn sign_in(
|
||||
session: UserSessionFromSession,
|
||||
Query(params): Query<oidc::SignInParams>,
|
||||
TypedHeader(cookies): TypedHeader<headers::Cookie>,
|
||||
Extension(redis_client): Extension<RedisClient>,
|
||||
) -> Result<(HeaderMap, Redirect), CustomError> {
|
||||
let (nonce, headers) = match session {
|
||||
UserSessionFromSession::Found(nonce) => (nonce, HeaderMap::new()),
|
||||
UserSessionFromSession::Invalid(header) => {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(header::SET_COOKIE, header);
|
||||
return Ok((
|
||||
headers,
|
||||
Redirect::to(
|
||||
format!(
|
||||
"/authorize?client_id={}&redirect_uri={}&scope=openid&response_type=code&state={}",
|
||||
¶ms.client_id.clone(),
|
||||
¶ms.redirect_uri.to_string(),
|
||||
¶ms.state,
|
||||
)
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("Could not parse URI: {}", e))?,
|
||||
),
|
||||
));
|
||||
}
|
||||
UserSessionFromSession::Created { .. } => {
|
||||
return Ok((
|
||||
HeaderMap::new(),
|
||||
Redirect::to(
|
||||
format!(
|
||||
"/authorize?client_id={}&redirect_uri={}&scope=openid&response_type=code&state={}",
|
||||
¶ms.client_id.clone(),
|
||||
¶ms.redirect_uri.to_string(),
|
||||
¶ms.state,
|
||||
)
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("Could not parse URI: {}", e))?,
|
||||
),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let url = oidc::sign_in(params, Some(nonce), cookies, &redis_client).await?;
|
||||
|
||||
Ok((
|
||||
headers,
|
||||
Redirect::to(
|
||||
url.as_str()
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("Could not parse URI: {}", e))?,
|
||||
),
|
||||
) -> Result<Redirect, CustomError> {
|
||||
let url = oidc::sign_in(params, cookies, &redis_client).await?;
|
||||
Ok(Redirect::to(
|
||||
url.as_str()
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("Could not parse URI: {}", e))?,
|
||||
))
|
||||
// TODO clear session
|
||||
}
|
||||
|
||||
async fn register(
|
||||
@@ -434,11 +355,6 @@ pub async fn main() {
|
||||
.layer(AddExtensionLayer::new(private_key))
|
||||
.layer(AddExtensionLayer::new(config.clone()))
|
||||
.layer(AddExtensionLayer::new(redis_client))
|
||||
.layer(AddExtensionLayer::new(
|
||||
RedisSessionStore::new(config.redis_url.clone())
|
||||
.unwrap()
|
||||
.with_prefix("async-sessions/"),
|
||||
))
|
||||
.layer(TraceLayer::new_for_http());
|
||||
|
||||
let addr = SocketAddr::from((config.address, config.port));
|
||||
|
||||
30
src/db/cf.rs
30
src/db/cf.rs
@@ -1,6 +1,5 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
// use cached::{stores::TimedCache, Cached};
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use matchit::Node;
|
||||
use std::collections::HashMap;
|
||||
@@ -109,7 +108,6 @@ impl DBClient for CFClient {
|
||||
.map_err(|e| anyhow!("Failed to serialize client entry: {}", e))?,
|
||||
)
|
||||
.map_err(|e| anyhow!("Failed to build KV put: {}", e))?
|
||||
// TODO put some sort of expiration for dynamic registration
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to put KV: {}", e))?;
|
||||
@@ -202,4 +200,32 @@ impl DBClient for CFClient {
|
||||
code => Err(anyhow!("Error fetching from Durable Object: {}", code)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn set_session(&self, id: String, entry: SessionEntry) -> Result<()> {
|
||||
self.ctx
|
||||
.kv(KV_NAMESPACE)
|
||||
.map_err(|e| anyhow!("Failed to get KV store: {}", e))?
|
||||
.put(
|
||||
&format!("{}/{}", KV_SESSION_PREFIX, id),
|
||||
serde_json::to_string(&entry)
|
||||
.map_err(|e| anyhow!("Failed to serialize client entry: {}", e))?,
|
||||
)
|
||||
.map_err(|e| anyhow!("Failed to build KV put: {}", e))?
|
||||
.expiration_ttl(SESSION_LIFETIME)
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to put KV: {}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_session(&self, id: String) -> Result<Option<SessionEntry>> {
|
||||
Ok(self
|
||||
.ctx
|
||||
.kv(KV_NAMESPACE)
|
||||
.map_err(|e| anyhow!("Failed to get KV store: {}", e))?
|
||||
.get(&format!("{}/{}", KV_SESSION_PREFIX, id))
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to get KV: {}", e))?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ mod cf;
|
||||
pub use cf::CFClient;
|
||||
|
||||
const KV_CLIENT_PREFIX: &str = "clients";
|
||||
const KV_SESSION_PREFIX: &str = "sessions";
|
||||
pub const ENTRY_LIFETIME: usize = 30;
|
||||
pub const SESSION_LIFETIME: u64 = 300; // 5min
|
||||
pub const SESSION_COOKIE_NAME: &str = "session";
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct CodeEntry {
|
||||
@@ -33,6 +36,14 @@ pub struct ClientEntry {
|
||||
pub access_token: Option<RegistrationAccessToken>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct SessionEntry {
|
||||
pub siwe_nonce: String,
|
||||
pub oidc_nonce: Option<Nonce>,
|
||||
pub secret: String,
|
||||
pub signin_count: u64,
|
||||
}
|
||||
|
||||
// Using a trait to easily pass async functions with async_trait
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
@@ -42,4 +53,6 @@ pub trait DBClient {
|
||||
async fn delete_client(&self, client_id: String) -> Result<()>;
|
||||
async fn set_code(&self, code: String, code_entry: CodeEntry) -> Result<()>;
|
||||
async fn get_code(&self, code: String) -> Result<Option<CodeEntry>>;
|
||||
async fn set_session(&self, id: String, entry: SessionEntry) -> Result<()>;
|
||||
async fn get_session(&self, id: String) -> Result<Option<SessionEntry>>;
|
||||
}
|
||||
|
||||
@@ -98,4 +98,40 @@ impl DBClient for RedisClient {
|
||||
.map_err(|e| anyhow!("Failed to deserialize code: {}", e))?;
|
||||
Ok(Some(code_entry))
|
||||
}
|
||||
|
||||
async fn set_session(&self, id: String, entry: SessionEntry) -> Result<()> {
|
||||
let mut conn = self
|
||||
.pool
|
||||
.get()
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to get connection to database: {}", e))?;
|
||||
|
||||
conn.set_ex(
|
||||
format!("{}/{}", KV_SESSION_PREFIX, id),
|
||||
serde_json::to_string(&entry)
|
||||
.map_err(|e| anyhow!("Failed to serialize session entry: {}", e))?,
|
||||
SESSION_LIFETIME.try_into().unwrap(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to set kv: {}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_session(&self, id: String) -> Result<Option<SessionEntry>> {
|
||||
let mut conn = self
|
||||
.pool
|
||||
.get()
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to get connection to database: {}", e))?;
|
||||
let entry: Option<String> = conn
|
||||
.get(format!("{}/{}", KV_SESSION_PREFIX, id))
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to get kv: {}", e))?;
|
||||
if let Some(e) = entry {
|
||||
Ok(serde_json::from_str(&e)
|
||||
.map_err(|e| anyhow!("Failed to deserialize session entry: {}", e))?)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ mod config;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod oidc;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod session;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use axum_lib::main as axum_main;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
75
src/oidc.rs
75
src/oidc.rs
@@ -1,5 +1,6 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use chrono::{Duration, Utc};
|
||||
use cookie::Cookie;
|
||||
use ethers_core::{types::H160, utils::to_checksum};
|
||||
use headers::{self, authorization::Bearer};
|
||||
use hex::FromHex;
|
||||
@@ -315,9 +316,8 @@ pub struct AuthorizeParams {
|
||||
|
||||
pub async fn authorize(
|
||||
params: AuthorizeParams,
|
||||
nonce: String,
|
||||
db_client: &DBClientType,
|
||||
) -> Result<String, CustomError> {
|
||||
) -> Result<(String, Box<Cookie<'_>>), CustomError> {
|
||||
let client_entry = db_client
|
||||
.get_client(params.client_id.clone())
|
||||
.await
|
||||
@@ -328,6 +328,12 @@ pub async fn authorize(
|
||||
));
|
||||
}
|
||||
|
||||
let nonce: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(16)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
|
||||
let mut r_u = params.redirect_uri.clone().url().clone();
|
||||
r_u.set_query(None);
|
||||
let mut r_us: Vec<Url> = client_entry
|
||||
@@ -397,15 +403,45 @@ pub async fn authorize(
|
||||
}
|
||||
}
|
||||
|
||||
let session_id = Uuid::new_v4();
|
||||
let session_secret: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(16)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
db_client
|
||||
.set_session(
|
||||
session_id.to_string(),
|
||||
SessionEntry {
|
||||
siwe_nonce: nonce.clone(),
|
||||
oidc_nonce: params.nonce.clone(),
|
||||
secret: session_secret.clone(),
|
||||
signin_count: 0,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
let session_cookie = Cookie::build(SESSION_COOKIE_NAME, session_id.to_string())
|
||||
// .domain(base)
|
||||
// .path("/")
|
||||
.secure(true)
|
||||
.http_only(true)
|
||||
.max_age(cookie::time::Duration::seconds(
|
||||
SESSION_LIFETIME.try_into().unwrap(),
|
||||
))
|
||||
.finish();
|
||||
|
||||
let domain = params.redirect_uri.url().host().unwrap();
|
||||
let oidc_nonce_param = if let Some(n) = ¶ms.nonce {
|
||||
format!("&oidc_nonce={}", n.secret())
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
Ok(format!(
|
||||
"/?nonce={}&domain={}&redirect_uri={}&state={}&client_id={}{}",
|
||||
nonce, domain, *params.redirect_uri, state, params.client_id, oidc_nonce_param
|
||||
Ok((
|
||||
format!(
|
||||
"/?nonce={}&domain={}&redirect_uri={}&state={}&client_id={}{}",
|
||||
nonce, domain, *params.redirect_uri, state, params.client_id, oidc_nonce_param
|
||||
),
|
||||
Box::new(session_cookie),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -467,10 +503,29 @@ pub struct SignInParams {
|
||||
|
||||
pub async fn sign_in(
|
||||
params: SignInParams,
|
||||
expected_nonce: Option<String>,
|
||||
// cookies_header: String,
|
||||
cookies: headers::Cookie,
|
||||
db_client: &DBClientType,
|
||||
) -> Result<Url, CustomError> {
|
||||
// TODO redirect on session errors
|
||||
let session_id = if let Some(c) = cookies.get(SESSION_COOKIE_NAME) {
|
||||
c
|
||||
} else {
|
||||
return Err(CustomError::BadRequest(
|
||||
"Session cookie not found".to_string(),
|
||||
));
|
||||
};
|
||||
let session_entry = if let Some(e) = db_client.get_session(session_id.to_string()).await? {
|
||||
e
|
||||
} else {
|
||||
return Err(CustomError::BadRequest("Session not found".to_string()));
|
||||
};
|
||||
if session_entry.signin_count > 0 {
|
||||
return Err(CustomError::BadRequest(
|
||||
"Session has already logged in".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let siwe_cookie: SiweCookie = match cookies.get(SIWE_COOKIE_KEY) {
|
||||
Some(c) => serde_json::from_str(
|
||||
&decode(c).map_err(|e| anyhow!("Could not decode siwe cookie: {}", e))?,
|
||||
@@ -508,7 +563,7 @@ pub async fn sign_in(
|
||||
if domain.to_string() != *siwe_cookie.message.resources.get(0).unwrap().to_string() {
|
||||
return Err(anyhow!("Conflicting domains in message and redirect").into());
|
||||
}
|
||||
if expected_nonce.is_some() && expected_nonce.unwrap() != siwe_cookie.message.nonce {
|
||||
if session_entry.siwe_nonce != siwe_cookie.message.nonce {
|
||||
return Err(anyhow!("Conflicting nonces in message and session").into());
|
||||
}
|
||||
|
||||
@@ -520,6 +575,12 @@ pub async fn sign_in(
|
||||
auth_time: Utc::now(),
|
||||
};
|
||||
|
||||
let mut new_session_entry = session_entry.clone();
|
||||
new_session_entry.signin_count += 1;
|
||||
db_client
|
||||
.set_session(session_id.to_string(), new_session_entry)
|
||||
.await?;
|
||||
|
||||
let code = Uuid::new_v4();
|
||||
db_client.set_code(code.to_string(), code_entry).await?;
|
||||
|
||||
|
||||
119
src/session.rs
119
src/session.rs
@@ -1,119 +0,0 @@
|
||||
use async_redis_session::RedisSessionStore;
|
||||
use async_session::{Session, SessionStore as _};
|
||||
use axum::{
|
||||
async_trait,
|
||||
extract::{Extension, FromRequest, RequestParts},
|
||||
http::{self, header::HeaderValue, StatusCode},
|
||||
};
|
||||
use cookie::Cookie;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::debug;
|
||||
use uuid::Uuid;
|
||||
|
||||
const SESSION_COOKIE_NAME: &str = "session";
|
||||
const SESSION_KEY: &str = "user_session";
|
||||
|
||||
pub enum UserSessionFromSession {
|
||||
Found(String),
|
||||
Created { header: HeaderValue, nonce: String },
|
||||
Invalid(HeaderValue),
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for UserSessionFromSession
|
||||
where
|
||||
B: Send,
|
||||
{
|
||||
type Rejection = (StatusCode, String);
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
let Extension(store) = match Extension::<RedisSessionStore>::from_request(req).await {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("`MemoryStore` extension missing: {}", e),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let headers = if let Some(h) = req.headers() {
|
||||
h
|
||||
} else {
|
||||
return Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"other extractor taken headers".to_string(),
|
||||
));
|
||||
};
|
||||
|
||||
let session_cookie: Cookie = if let Some(session_cookie) = headers
|
||||
.get(http::header::COOKIE)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.map(|header| {
|
||||
header
|
||||
.split(';')
|
||||
.map(|cookie| Cookie::parse(cookie).ok())
|
||||
.find(|cookie| {
|
||||
cookie.is_some() && cookie.as_ref().unwrap().name() == SESSION_COOKIE_NAME
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.flatten()
|
||||
{
|
||||
session_cookie
|
||||
} else {
|
||||
let user_session = UserSession::new();
|
||||
let mut session = Session::new();
|
||||
session.insert(SESSION_KEY, user_session.clone()).unwrap();
|
||||
let cookie = store.store_session(session).await.unwrap().unwrap();
|
||||
|
||||
return Ok(Self::Created {
|
||||
header: Cookie::new(SESSION_COOKIE_NAME, cookie)
|
||||
.to_string()
|
||||
.parse()
|
||||
.unwrap(),
|
||||
nonce: user_session.nonce,
|
||||
});
|
||||
};
|
||||
|
||||
let session = match store.load_session(session_cookie.value().to_string()).await {
|
||||
Ok(Some(s)) => s,
|
||||
_ => {
|
||||
debug!("Could not load session");
|
||||
let mut cookie = session_cookie.clone();
|
||||
cookie.make_removal();
|
||||
return Ok(Self::Invalid(cookie.to_string().parse().unwrap()));
|
||||
}
|
||||
};
|
||||
let user_session = if let Some(user_session) = session.get::<UserSession>(SESSION_KEY) {
|
||||
user_session
|
||||
} else {
|
||||
debug!("No `user_session` found in session");
|
||||
let mut cookie = session_cookie.clone();
|
||||
cookie.make_removal();
|
||||
return Ok(Self::Invalid(cookie.to_string().parse().unwrap()));
|
||||
};
|
||||
|
||||
Ok(Self::Found(user_session.nonce))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
struct UserSession {
|
||||
id: Uuid,
|
||||
nonce: String,
|
||||
}
|
||||
|
||||
impl UserSession {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
id: Uuid::new_v4(),
|
||||
nonce: rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(16)
|
||||
.map(char::from)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ use headers::{
|
||||
authorization::{Basic, Bearer, Credentials},
|
||||
Authorization, ContentType, Header, HeaderValue,
|
||||
};
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use rsa::{pkcs1::FromRsaPrivateKey, RsaPrivateKey};
|
||||
use worker::*;
|
||||
|
||||
@@ -197,7 +196,6 @@ pub async fn main(req: Request, env: Env) -> Result<Response> {
|
||||
}
|
||||
.and_then(|r| r.with_cors(&get_cors()))
|
||||
})
|
||||
// TODO add browser session
|
||||
.get_async(oidc::AUTHORIZE_PATH, |req, ctx| async move {
|
||||
let base_url: Url = ctx.var(BASE_URL_KEY)?.to_string().parse().unwrap();
|
||||
let url = req.url()?;
|
||||
@@ -206,15 +204,18 @@ pub async fn main(req: Request, env: Env) -> Result<Response> {
|
||||
Ok(p) => p,
|
||||
Err(_) => return CustomError::BadRequest("Bad query params".to_string()).into(),
|
||||
};
|
||||
let nonce = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(16)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
let url = req.url()?;
|
||||
let db_client = CFClient { ctx, url };
|
||||
match oidc::authorize(params, nonce, &db_client).await {
|
||||
Ok(url) => Response::redirect(base_url.join(&url).unwrap()),
|
||||
match oidc::authorize(params, &db_client).await {
|
||||
Ok((url, session_cookie)) => {
|
||||
Response::redirect(base_url.join(&url).unwrap()).map(|r| {
|
||||
let mut headers = r.headers().clone();
|
||||
headers
|
||||
.set("set-cookie", &session_cookie.to_string())
|
||||
.unwrap();
|
||||
r.with_headers(headers)
|
||||
})
|
||||
}
|
||||
Err(e) => match e {
|
||||
CustomError::Redirect(url) => {
|
||||
CustomError::Redirect(base_url.join(&url).unwrap().to_string())
|
||||
@@ -320,7 +321,7 @@ pub async fn main(req: Request, env: Env) -> Result<Response> {
|
||||
}
|
||||
let url = req.url()?;
|
||||
let db_client = CFClient { ctx, url };
|
||||
match oidc::sign_in(params, None, cookies.unwrap(), &db_client).await {
|
||||
match oidc::sign_in(params, cookies.unwrap(), &db_client).await {
|
||||
Ok(url) => Response::redirect(url),
|
||||
Err(e) => e.into(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user