Compare commits
1 Commits
master
...
renovate/l
Author | SHA1 | Date | |
---|---|---|---|
40e7be73d5 |
784
Cargo.lock
generated
784
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -18,13 +18,13 @@ serde_json = "1.0.128"
|
|||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
env_logger = "0.11.3"
|
env_logger = "0.11.3"
|
||||||
serde = { version = "1.0.210", features = ["derive"] }
|
serde = { version = "1.0.210", features = ["derive"] }
|
||||||
bcrypt = "0.17.0"
|
bcrypt = "0.16.0"
|
||||||
uuid = { version = "1.8.0", features = ["v4"] }
|
uuid = { version = "1.8.0", features = ["v4"] }
|
||||||
mime_guess = "2.0.4"
|
mime_guess = "2.0.4"
|
||||||
askama = "0.12.1"
|
askama = "0.12.1"
|
||||||
futures-util = "0.3.30"
|
futures-util = "0.3.30"
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
rand = "0.9.0"
|
rand = "0.8.5"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
jwt-simple = { version = "0.12.10", default-features = false, features = ["pure-rust"] }
|
jwt-simple = { version = "0.12.10", default-features = false, features = ["pure-rust"] }
|
||||||
digest = "0.10.7"
|
digest = "0.10.7"
|
||||||
|
@ -16,7 +16,7 @@ use crate::constants::*;
|
|||||||
use crate::controllers::base_controller::{build_fatal_error_page, redirect_user};
|
use crate::controllers::base_controller::{build_fatal_error_page, redirect_user};
|
||||||
use crate::data::action_logger::{Action, ActionLogger};
|
use crate::data::action_logger::{Action, ActionLogger};
|
||||||
use crate::data::app_config::AppConfig;
|
use crate::data::app_config::AppConfig;
|
||||||
use crate::data::client::{AdditionalClaims, ClientID, ClientManager};
|
use crate::data::client::{AdditionalClaims, AuthenticationFlow, ClientID, ClientManager};
|
||||||
use crate::data::code_challenge::CodeChallenge;
|
use crate::data::code_challenge::CodeChallenge;
|
||||||
use crate::data::current_user::CurrentUser;
|
use crate::data::current_user::CurrentUser;
|
||||||
use crate::data::id_token::IdToken;
|
use crate::data::id_token::IdToken;
|
||||||
@ -50,9 +50,7 @@ pub async fn get_configuration(req: HttpRequest) -> impl Responder {
|
|||||||
host
|
host
|
||||||
);
|
);
|
||||||
|
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().json(OpenIDConfig {
|
||||||
.insert_header(("access-control-allow-origin", "*"))
|
|
||||||
.json(OpenIDConfig {
|
|
||||||
issuer: AppConfig::get().website_origin.clone(),
|
issuer: AppConfig::get().website_origin.clone(),
|
||||||
authorization_endpoint: AppConfig::get().full_url(AUTHORIZE_URI),
|
authorization_endpoint: AppConfig::get().full_url(AUTHORIZE_URI),
|
||||||
token_endpoint: curr_origin.clone() + TOKEN_URI,
|
token_endpoint: curr_origin.clone() + TOKEN_URI,
|
||||||
@ -220,8 +218,8 @@ pub async fn authorize(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
match (client.has_secret(), query.response_type.as_str()) {
|
match (client.auth_flow(), query.response_type.as_str()) {
|
||||||
(_, "code") => {
|
(AuthenticationFlow::AuthorizationCode, "code") => {
|
||||||
// Save all authentication information in memory
|
// Save all authentication information in memory
|
||||||
let session = Session {
|
let session = Session {
|
||||||
session_id: SessionID(rand_str(OPEN_ID_SESSION_LEN)),
|
session_id: SessionID(rand_str(OPEN_ID_SESSION_LEN)),
|
||||||
@ -263,8 +261,7 @@ pub async fn authorize(
|
|||||||
.finish())
|
.finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
// id_token is available only if user has no secret configured
|
(AuthenticationFlow::Implicit, "id_token") => {
|
||||||
(false, "id_token") => {
|
|
||||||
let id_token = IdToken {
|
let id_token = IdToken {
|
||||||
issuer: AppConfig::get().website_origin.to_string(),
|
issuer: AppConfig::get().website_origin.to_string(),
|
||||||
subject_identifier: user.uid.0.clone(),
|
subject_identifier: user.uid.0.clone(),
|
||||||
@ -296,11 +293,11 @@ pub async fn authorize(
|
|||||||
.finish())
|
.finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
(secret, code) => {
|
(flow, code) => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"For client {:?}, configured with secret {:?}, made request with code {}",
|
"For client {:?}, configured with flow {:?}, made request with code {}",
|
||||||
client.id,
|
client.id,
|
||||||
secret,
|
flow,
|
||||||
code
|
code
|
||||||
);
|
);
|
||||||
Ok(error_redirect(
|
Ok(error_redirect(
|
||||||
@ -369,7 +366,9 @@ pub async fn token(
|
|||||||
let (client_id, client_secret) =
|
let (client_id, client_secret) =
|
||||||
match (&query.client_id, &query.client_secret, authorization_header) {
|
match (&query.client_id, &query.client_secret, authorization_header) {
|
||||||
// post authentication
|
// post authentication
|
||||||
(Some(client_id), client_secret, None) => (client_id.clone(), client_secret.clone()),
|
(Some(client_id), Some(client_secret), None) => {
|
||||||
|
(client_id.clone(), client_secret.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
// Basic authentication
|
// Basic authentication
|
||||||
(_, None, Some(v)) => {
|
(_, None, Some(v)) => {
|
||||||
@ -400,8 +399,8 @@ pub async fn token(
|
|||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
match decode.split_once(':') {
|
match decode.split_once(':') {
|
||||||
None => (ClientID(decode), None),
|
None => (ClientID(decode), "".to_string()),
|
||||||
Some((id, secret)) => (ClientID(id.to_string()), Some(secret.to_string())),
|
Some((id, secret)) => (ClientID(id.to_string()), secret.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +418,7 @@ pub async fn token(
|
|||||||
.ok_or_else(|| ErrorUnauthorized("Client not found"))?;
|
.ok_or_else(|| ErrorUnauthorized("Client not found"))?;
|
||||||
|
|
||||||
// Retrieving token requires the client to have a defined secret
|
// Retrieving token requires the client to have a defined secret
|
||||||
if client.secret != client_secret {
|
if client.secret != Some(client_secret) {
|
||||||
return Ok(error_response(
|
return Ok(error_response(
|
||||||
&query,
|
&query,
|
||||||
"invalid_request",
|
"invalid_request",
|
||||||
@ -609,9 +608,8 @@ pub async fn token(
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok()
|
||||||
.insert_header(("Cache-Control", "no-store"))
|
.append_header(("Cache-Control", "no-store"))
|
||||||
.insert_header(("Pragma", "no-cache"))
|
.append_header(("Pragam", "no-cache"))
|
||||||
.insert_header(("access-control-allow-origin", "*"))
|
|
||||||
.json(token_response))
|
.json(token_response))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,12 @@ use std::collections::HashMap;
|
|||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
|
||||||
pub struct ClientID(pub String);
|
pub struct ClientID(pub String);
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum AuthenticationFlow {
|
||||||
|
AuthorizationCode,
|
||||||
|
Implicit,
|
||||||
|
}
|
||||||
|
|
||||||
pub type AdditionalClaims = HashMap<String, Value>;
|
pub type AdditionalClaims = HashMap<String, Value>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
@ -55,9 +61,12 @@ impl PartialEq for Client {
|
|||||||
impl Eq for Client {}
|
impl Eq for Client {}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Check if the client has a secret defined
|
/// Get the client authentication flow
|
||||||
pub fn has_secret(&self) -> bool {
|
pub fn auth_flow(&self) -> AuthenticationFlow {
|
||||||
self.secret.is_some()
|
match self.secret {
|
||||||
|
None => AuthenticationFlow::Implicit,
|
||||||
|
Some(_) => AuthenticationFlow::AuthorizationCode,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process a single claim value
|
/// Process a single claim value
|
||||||
|
@ -21,7 +21,7 @@ pub struct TotpKey {
|
|||||||
impl TotpKey {
|
impl TotpKey {
|
||||||
/// Generate a new TOTP key
|
/// Generate a new TOTP key
|
||||||
pub fn new_random() -> Self {
|
pub fn new_random() -> Self {
|
||||||
let random_bytes = rand::rng().random::<[u8; 20]>();
|
let random_bytes = rand::thread_rng().gen::<[u8; 20]>();
|
||||||
Self {
|
Self {
|
||||||
encoded: base32::encode(BASE32_ALPHABET, &random_bytes),
|
encoded: base32::encode(BASE32_ALPHABET, &random_bytes),
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
use lazy_regex::regex_find;
|
use lazy_regex::regex_find;
|
||||||
use rand::distr::{Alphanumeric, SampleString};
|
use rand::distributions::Alphanumeric;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
/// Generate a random string of a given size
|
/// Generate a random string of a given size
|
||||||
pub fn rand_str(len: usize) -> String {
|
pub fn rand_str(len: usize) -> String {
|
||||||
Alphanumeric.sample_string(&mut rand::rng(), len)
|
rand::thread_rng()
|
||||||
|
.sample_iter(&Alphanumeric)
|
||||||
|
.map(char::from)
|
||||||
|
.take(len)
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse environment variables
|
/// Parse environment variables
|
||||||
|
Loading…
x
Reference in New Issue
Block a user