Compare commits
36 Commits
renovate/l
...
master
Author | SHA1 | Date | |
---|---|---|---|
c9d41f2517 | |||
1a1a41d5dc | |||
d01311abf1 | |||
a73ad4bf41 | |||
4a248e84ac | |||
e650fe0c29 | |||
473abb2d38 | |||
1b743c86bf | |||
8c25e2aa4c | |||
f7e4eb955c | |||
7d521ef040 | |||
c59e7b96db | |||
a0d204ad09 | |||
a06be2e889 | |||
42862aea7f | |||
8173ac5bc1 | |||
79a00ff7ad | |||
f2e4d82f87 | |||
022073f26a | |||
c22fcdab74 | |||
672267d521 | |||
c26a3af253 | |||
84d69de09b | |||
76faa33c4e | |||
fb0ebde748 | |||
e0f33c133b | |||
8a0ef75295 | |||
a4f73db82e | |||
31ad52607f | |||
a201f175a2 | |||
f5eaecc189 | |||
6c18a58c43 | |||
677b4221eb | |||
ae92f8f405 | |||
16083a7624 | |||
09da003f35 |
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.16.0"
|
bcrypt = "0.17.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.8.5"
|
rand = "0.9.0"
|
||||||
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, AuthenticationFlow, ClientID, ClientManager};
|
use crate::data::client::{AdditionalClaims, 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,7 +50,9 @@ pub async fn get_configuration(req: HttpRequest) -> impl Responder {
|
|||||||
host
|
host
|
||||||
);
|
);
|
||||||
|
|
||||||
HttpResponse::Ok().json(OpenIDConfig {
|
HttpResponse::Ok()
|
||||||
|
.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,
|
||||||
@ -218,8 +220,8 @@ pub async fn authorize(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
match (client.auth_flow(), query.response_type.as_str()) {
|
match (client.has_secret(), query.response_type.as_str()) {
|
||||||
(AuthenticationFlow::AuthorizationCode, "code") => {
|
(_, "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)),
|
||||||
@ -261,7 +263,8 @@ pub async fn authorize(
|
|||||||
.finish())
|
.finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
(AuthenticationFlow::Implicit, "id_token") => {
|
// id_token is available only if user has no secret configured
|
||||||
|
(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(),
|
||||||
@ -293,11 +296,11 @@ pub async fn authorize(
|
|||||||
.finish())
|
.finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
(flow, code) => {
|
(secret, code) => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"For client {:?}, configured with flow {:?}, made request with code {}",
|
"For client {:?}, configured with secret {:?}, made request with code {}",
|
||||||
client.id,
|
client.id,
|
||||||
flow,
|
secret,
|
||||||
code
|
code
|
||||||
);
|
);
|
||||||
Ok(error_redirect(
|
Ok(error_redirect(
|
||||||
@ -366,9 +369,7 @@ 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), Some(client_secret), None) => {
|
(Some(client_id), client_secret, None) => (client_id.clone(), client_secret.clone()),
|
||||||
(client_id.clone(), client_secret.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic authentication
|
// Basic authentication
|
||||||
(_, None, Some(v)) => {
|
(_, None, Some(v)) => {
|
||||||
@ -399,8 +400,8 @@ pub async fn token(
|
|||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
match decode.split_once(':') {
|
match decode.split_once(':') {
|
||||||
None => (ClientID(decode), "".to_string()),
|
None => (ClientID(decode), None),
|
||||||
Some((id, secret)) => (ClientID(id.to_string()), secret.to_string()),
|
Some((id, secret)) => (ClientID(id.to_string()), Some(secret.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,7 +419,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 != Some(client_secret) {
|
if client.secret != client_secret {
|
||||||
return Ok(error_response(
|
return Ok(error_response(
|
||||||
&query,
|
&query,
|
||||||
"invalid_request",
|
"invalid_request",
|
||||||
@ -608,8 +609,9 @@ pub async fn token(
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok()
|
||||||
.append_header(("Cache-Control", "no-store"))
|
.insert_header(("Cache-Control", "no-store"))
|
||||||
.append_header(("Pragam", "no-cache"))
|
.insert_header(("Pragma", "no-cache"))
|
||||||
|
.insert_header(("access-control-allow-origin", "*"))
|
||||||
.json(token_response))
|
.json(token_response))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,12 +7,6 @@ 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)]
|
||||||
@ -61,12 +55,9 @@ impl PartialEq for Client {
|
|||||||
impl Eq for Client {}
|
impl Eq for Client {}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Get the client authentication flow
|
/// Check if the client has a secret defined
|
||||||
pub fn auth_flow(&self) -> AuthenticationFlow {
|
pub fn has_secret(&self) -> bool {
|
||||||
match self.secret {
|
self.secret.is_some()
|
||||||
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::thread_rng().gen::<[u8; 20]>();
|
let random_bytes = rand::rng().random::<[u8; 20]>();
|
||||||
Self {
|
Self {
|
||||||
encoded: base32::encode(BASE32_ALPHABET, &random_bytes),
|
encoded: base32::encode(BASE32_ALPHABET, &random_bytes),
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
use lazy_regex::regex_find;
|
use lazy_regex::regex_find;
|
||||||
use rand::distributions::Alphanumeric;
|
use rand::distr::{Alphanumeric, SampleString};
|
||||||
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 {
|
||||||
rand::thread_rng()
|
Alphanumeric.sample_string(&mut rand::rng(), len)
|
||||||
.sample_iter(&Alphanumeric)
|
|
||||||
.map(char::from)
|
|
||||||
.take(len)
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse environment variables
|
/// Parse environment variables
|
||||||
|
Loading…
x
Reference in New Issue
Block a user