Rework browser sessions

This commit is contained in:
Simon Bihel
2022-02-21 11:29:37 +00:00
parent 950a493dc4
commit 66b2c51339
10 changed files with 173 additions and 617 deletions

View File

@@ -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={}{}",
&params.client_id,
&params.redirect_uri.to_string(),
&params.scope.to_string(),
&params.response_type.unwrap_or(CoreResponseType::Code).as_ref(),
&params.state.unwrap_or_default(),
&params.client_id,
&params.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={}",
&params.client_id.clone(),
&params.redirect_uri.to_string(),
&params.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={}",
&params.client_id.clone(),
&params.redirect_uri.to_string(),
&params.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));