Skip to content

Commit

Permalink
feat: cookie authentication #512
Browse files Browse the repository at this point in the history
  • Loading branch information
Thom committed Oct 26, 2022
1 parent 379e3e0 commit 6b21d21
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Changes to JS assets are not included here, but in [`atomic-data-browser`'s CHAN
- Add parent parameter to search endpoint which scopes a search to only the descendants of the given resource. #226
- Bookmark endpoint now also retrieves `og:image` and `og:description` #510
- Give server agent rights to edit all resources, fix issue with accepting invites in private drives #521
- Add cookie based authentication #512

## [v0.33.1] - 2022-09-25

Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ actix-cors = "0.6"
actix-files = "0.6"
actix-multipart = "0.4"
actix-web-actors = "4"
base64 = "0.13"
chrono = "0.4"
colored = "2"
dialoguer = "0.10"
directories = ">= 2, < 5"
dotenv = "0.15"
futures = "0.3"
percent-encoding = "2.2.0"
promptly = "0.3"
regex = "1"
rio_api = "0.7"
Expand Down
59 changes: 57 additions & 2 deletions server/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//! Functions useful in the server

use actix_web::http::header::HeaderMap;
use actix_web::cookie::Cookie;
use actix_web::http::header::{HeaderMap, HeaderValue};
use atomic_lib::authentication::AuthValues;
use percent_encoding::percent_decode_str;

use crate::errors::{AppErrorType, AtomicServerError};
use crate::{appstate::AppState, content_types::ContentType, errors::AtomicServerResult};

// Returns None if the string is empty.
Expand Down Expand Up @@ -56,6 +59,44 @@ pub fn get_auth_headers(
}
}

pub fn get_auth_from_cookie(
map: &HeaderMap,
requested_subject: &String,
) -> Option<AtomicServerResult<Option<AuthValues>>> {
let encoded_session = session_cookie_from_header(map.get("Cookie")?)?;

let session = base64::decode(encoded_session).ok()?;
let session_str = std::str::from_utf8(&session).ok()?;
let values: Result<AuthValues, AtomicServerError> =
serde_json::from_str(session_str).map_err(|_| AtomicServerError {
message: "Malformed authentication resource".to_string(),
error_type: AppErrorType::Unauthorized,
error_resource: None,
});

if let Ok(auth_values) = values {
if auth_values.requested_subject.eq(requested_subject) {
return Some(Err(AtomicServerError {
message: "Wrong requested subject".to_string(),
error_type: AppErrorType::Unauthorized,
error_resource: None,
}));
}

Some(Ok(Some(auth_values)))
} else {
Some(Err(values.err().unwrap()))
}
}

pub fn get_auth(
map: &HeaderMap,
requested_subject: String,
) -> AtomicServerResult<Option<AuthValues>> {
let cookie_result = get_auth_from_cookie(map, &requested_subject);
cookie_result.unwrap_or_else(|| get_auth_headers(map, requested_subject))
}

/// Checks for authentication headers and returns Some agent's subject if everything is well.
/// Skips these checks in public_mode and returns Ok(None).
#[tracing::instrument(skip(appstate))]
Expand All @@ -68,7 +109,7 @@ pub fn get_client_agent(
return Ok(None);
}
// Authentication check. If the user has no headers, continue with the Public Agent.
let auth_header_values = get_auth_headers(headers, requested_subject)?;
let auth_header_values = get_auth(headers, requested_subject)?;
let for_agent = atomic_lib::authentication::get_agent_from_auth_values_and_check(
auth_header_values,
&appstate.store,
Expand All @@ -94,3 +135,17 @@ pub fn try_extension(path: &str) -> Option<(ContentType, &str)> {
}
None
}

fn session_cookie_from_header(header: &HeaderValue) -> Option<String> {
let cookies: Vec<&str> = header.to_str().ok()?.split(';').collect();

for encoded_cookie in cookies {
let cookie = Cookie::parse(encoded_cookie).ok()?;
if cookie.name() == "atomic_session" {
let decoded = percent_decode_str(cookie.value()).decode_utf8().ok()?;
return Some(String::from(decoded));
}
}

None
}

0 comments on commit 6b21d21

Please sign in to comment.