INSECURE HACK TO BYPASS CORS UGH

This commit is contained in:
Brandon Thomas committed 2024-08-28 18:06:13 -04:00
1 parent b7091b8b07
commit 748e8a6d3e
4 files changed
+131 -9

No files matched your search

@@ -6,3 +6,4 @@ pub mod logout_handler;
pub mod password_reset_redeem_handler;
pub mod password_reset_request_handler;
pub mod session_info_handler;
pub mod session_token_info_handler;
@@ -0,0 +1,88 @@
use std::collections::BTreeSet;
use std::fmt;
use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::Json;
use log::warn;
use sqlx::MySqlPool;
use utoipa::ToSchema;
use enums::by_table::users::user_feature_flag::UserFeatureFlag;
use http_server_common::response::response_error_helpers::to_simple_json_error;
use tokens::tokens::users::UserToken;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager;
use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags;
use crate::http_server::session::session_checker::SessionChecker;
use crate::state::server_state::ServerState;
#[derive(Serialize, ToSchema)]
pub struct SessionTokenInfoSuccessResponse {
/// A signed session that can be sent as a header, bypassing cookies.
/// This is useful for API clients that don't support cookies or Google
/// browsers killing cross-domain cookies.
pub maybe_signed_session: Option<String>,
}
#[derive(Debug, ToSchema)]
pub enum SessionTokenInfoError {
NotAuthorized,
ServerError,
}
impl ResponseError for SessionTokenInfoError {
fn status_code(&self) -> StatusCode {
match *self {
SessionTokenInfoError::NotAuthorized => StatusCode::UNAUTHORIZED,
SessionTokenInfoError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
}
}
fn error_response(&self) -> HttpResponse {
let error_reason = match self {
SessionTokenInfoError::ServerError => "server error".to_string(),
SessionTokenInfoError::NotAuthorized => "not authorized".to_string(),
};
to_simple_json_error(&error_reason, self.status_code())
}
}
// NB: Not using derive_more::Display since Clion doesn't understand it.
impl fmt::Display for SessionTokenInfoError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
#[utoipa::path(
get,
tag = "Users",
path = "/v1/session_token",
responses(
(status = 200, description = "Success response", body = SessionTokenInfoSuccessResponse),
(status = 500, description = "Server error", body = SessionTokenInfoError),
),
)]
pub async fn session_token_info_handler(
http_request: HttpRequest,
session_checker: web::Data<SessionChecker>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<Json<SessionTokenInfoSuccessResponse>, SessionTokenInfoError>
{
let maybe_session_payload = server_state
.session_cookie_manager
.check_and_return_session_token_decodes(&http_request)
.map_err(|e| {
warn!("Session cookie decode error: {:?}", e);
SessionTokenInfoError::ServerError
})?;
Ok(Json(SessionTokenInfoSuccessResponse {
maybe_signed_session: maybe_session_payload,
}))
}
@@ -14,6 +14,7 @@ use crate::http_server::endpoints::users::logout_handler::logout_handler;
use crate::http_server::endpoints::users::password_reset_redeem_handler::password_reset_redeem_handler;
use crate::http_server::endpoints::users::password_reset_request_handler::password_reset_request_handler;
use crate::http_server::endpoints::users::session_info_handler::session_info_handler;
use crate::http_server::endpoints::users::session_token_info_handler::session_token_info_handler;
use crate::http_server::endpoints::w2l::list_user_w2l_inference_results::list_user_w2l_inference_results_handler;
use crate::http_server::endpoints::w2l::list_user_w2l_templates::list_user_w2l_templates_handler;
@@ -73,6 +74,11 @@ pub fn add_user_routes<T, B> (app: App<T>) -> App<T>
.route(web::get().to(session_info_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(
web::resource("/v1/session_token")
.route(web::get().to(session_token_info_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(
web::resource("/v1/password_reset/request")
.route(web::post().to(password_reset_request_handler))
@@ -80,15 +80,7 @@ impl HttpUserSessionManager {
request: &HttpRequest
) -> AnyhowResult<Option<HttpUserSessionPayload>>
{
let mut signed_session_payload= request.cookie(SESSION_COOKIE_NAME)
.map(|cookie| cookie.value().to_string());
if signed_session_payload.is_none() {
signed_session_payload = request.headers().get(SESSION_HEADER_NAME)
.map(|header| header.to_str())
.transpose()?
.map(|payload| payload.to_string());
}
let signed_session_payload = self.session_payload_from_request(request)?;
let signed_session_payload = match signed_session_payload {
Some(payload) => payload,
@@ -103,6 +95,41 @@ impl HttpUserSessionManager {
Ok(payload) => Ok(Some(payload)),
}
}
// NB: THIS IS ONLY FOR A QUICK HACK FOR FREAKING CORS UGH
// THIS IS A HUGE STUPID SECURITY VULN. DAMNIT GOOGLE DAMNIT CORS.
pub fn check_and_return_session_token_decodes(&self, request: &HttpRequest) -> AnyhowResult<Option<String>> {
let signed_session_payload = self.session_payload_from_request(request)?;
let signed_session_payload = match signed_session_payload {
Some(payload) => payload,
None => return Ok(None),
};
match self.payload_signer.decode(&signed_session_payload) {
Err(e) => {
warn!("Session cookie decode error: {:?}", e);
return Err(anyhow!("Could not decode session cookie: {:?}", e));
},
Ok(_payload) => {}, // Good! We'll just discard this.
}
Ok(Some(signed_session_payload))
}
fn session_payload_from_request(&self, request: &HttpRequest) -> AnyhowResult<Option<String>> {
let mut signed_session_payload= request.cookie(SESSION_COOKIE_NAME)
.map(|cookie| cookie.value().to_string());
if signed_session_payload.is_none() {
signed_session_payload = request.headers().get(SESSION_HEADER_NAME)
.map(|header| header.to_str())
.transpose()?
.map(|payload| payload.to_string());
}
Ok(signed_session_payload)
}
}
#[cfg(test)]