Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Fix #868 - allow Basic and Bearer auth #872

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion src/auth/oauth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ fn authenticate_client_token_request(
req: &HttpRequest,
client: &DBOAuthClient,
) -> Result<(), OAuthError> {
let client_secret = extract_authorization_header(req)?;
let header = extract_authorization_header(req)?;
let client_secret = header.as_str();
let hashed_client_secret = DBOAuthClient::hash_secret(client_secret);
if client.secret_hash != hashed_client_secret {
Err(OAuthError::error(
Expand Down
38 changes: 30 additions & 8 deletions src/auth/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::models::users::{Role, User, UserId, UserPayoutData};
use crate::queue::session::AuthQueue;
use crate::routes::internal::session::get_session_metadata;
use actix_web::HttpRequest;
use base64::Engine;
use chrono::Utc;
use reqwest::header::{HeaderValue, AUTHORIZATION};

Expand Down Expand Up @@ -92,11 +93,12 @@ pub async fn get_user_record_from_bearer_token<'a, 'b, E>(
where
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
{
let token = if let Some(token) = token {
token
} else {
extract_authorization_header(req)?
};
// This is silly, but the compiler kept complaining and this is the only way this would work
let mut temp: String = String::new();
if token.is_none() {
temp = extract_authorization_header(req)?;
}
let token = token.unwrap_or(&temp);

let possible_user = match token.split_once('_') {
Some(("mrp", _)) => {
Expand Down Expand Up @@ -178,13 +180,33 @@ where
Ok(possible_user)
}

pub fn extract_authorization_header(req: &HttpRequest) -> Result<&str, AuthenticationError> {
pub fn extract_authorization_header(req: &HttpRequest) -> Result<String, AuthenticationError> {
let headers = req.headers();
let token_val: Option<&HeaderValue> = headers.get(AUTHORIZATION);
token_val
let val = token_val
.ok_or_else(|| AuthenticationError::InvalidAuthMethod)?
.to_str()
.map_err(|_| AuthenticationError::InvalidCredentials)
.map_err(|_| AuthenticationError::InvalidCredentials)?;

return match val.split_once(' ') {
Some(("Bearer", token)) => Ok(token.trim().to_string()),
Some(("Basic", token)) => {
let decoded = base64::engine::general_purpose::STANDARD
.decode(token.trim())
.map_err(|_| AuthenticationError::InvalidCredentials)?;

let credentials: String =
String::from_utf8(decoded).map_err(|_| AuthenticationError::InvalidCredentials)?;

Ok(credentials
.split_once(':')
.ok_or_else(|| AuthenticationError::InvalidCredentials)?
.1
.trim()
.to_string())
}
Comment on lines +193 to +207

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's kind of awkward and unexpected to have the client_id be in the request payload, and the secret extracted from the Basic authentication header. Having any of these be in the request body is not recommended as per the standard.

This would work for my generic implementation (since they're sent in both ways for compatibility reasons), but a client might expect to only send them through Basic authorization, or only through the HTTP payload.

I know it adds some complexity to the authentication routine, that's the blessing of standards that are 14 years old! 😇 My intuition would be to change the signature to output an enum, so a variant can hold 2 strings and pass them along to oauth checks.

_ => Ok(val.trim().to_string()),
};
}

pub async fn check_is_moderator_from_headers<'a, 'b, E>(
Expand Down
9 changes: 1 addition & 8 deletions src/routes/v3/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
pub use super::ApiError;
use crate::util::cors::default_cors;
use actix_web::{web, HttpResponse};
use serde_json::json;
use actix_web::web;

pub mod analytics_get;
pub mod collections;
Expand Down Expand Up @@ -47,9 +46,3 @@ pub fn config(cfg: &mut web::ServiceConfig) {
.configure(versions::config),
);
}

pub async fn hello_world() -> Result<HttpResponse, ApiError> {
Ok(HttpResponse::Ok().json(json!({
"hello": "world",
})))
}
21 changes: 13 additions & 8 deletions src/search/indexing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,19 @@ pub async fn get_indexes_for_indexing(
let client = config.make_client();
let project_name = config.get_index_name("projects", next);
let project_filtered_name = config.get_index_name("projects_filtered", next);
let projects_index = create_or_update_index(&client, &project_name, Some(&[
"words",
"typo",
"proximity",
"attribute",
"exactness",
"sort",
]),).await?;
let projects_index = create_or_update_index(
&client,
&project_name,
Some(&[
"words",
"typo",
"proximity",
"attribute",
"exactness",
"sort",
]),
)
.await?;
let projects_filtered_index = create_or_update_index(
&client,
&project_filtered_name,
Expand Down
Loading