mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-10-07 16:54:33 +00:00
Review fix
This commit is contained in:
parent
bac049f2dd
commit
801b372e67
7 changed files with 35 additions and 125 deletions
|
@ -471,31 +471,42 @@
|
||||||
# SSO_ENABLED=false
|
# SSO_ENABLED=false
|
||||||
## Prevent users from logging in directly without going through SSO
|
## Prevent users from logging in directly without going through SSO
|
||||||
# SSO_ONLY=false
|
# SSO_ONLY=false
|
||||||
|
|
||||||
## On SSO Signup if a user with a matching email already exists make the association
|
## On SSO Signup if a user with a matching email already exists make the association
|
||||||
# SSO_SIGNUPS_MATCH_EMAIL=true
|
# SSO_SIGNUPS_MATCH_EMAIL=true
|
||||||
|
|
||||||
## Allow unknown email verification status. Allowing this with `SSO_SIGNUPS_MATCH_EMAIL=true` open potential account takeover.
|
## Allow unknown email verification status. Allowing this with `SSO_SIGNUPS_MATCH_EMAIL=true` open potential account takeover.
|
||||||
# SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION=false
|
# SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION=false
|
||||||
## Base URL of the OIDC server (auto-discovery is used)
|
## Base URL of the OIDC server (auto-discovery is used)
|
||||||
## - Should not include the `/.well-known/openid-configuration` part and no trailing `/`
|
## - Should not include the `/.well-known/openid-configuration` part and no trailing `/`
|
||||||
## - ${SSO_AUTHORITY}/.well-known/openid-configuration should return a json document: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse
|
## - ${SSO_AUTHORITY}/.well-known/openid-configuration should return a json document: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse
|
||||||
# SSO_AUTHORITY=https://auth.example.com
|
# SSO_AUTHORITY=https://auth.example.com
|
||||||
|
|
||||||
## Authorization request scopes. Optional SSO scopes, override if email and profile are not enough (`openid` is implicit).
|
## Authorization request scopes. Optional SSO scopes, override if email and profile are not enough (`openid` is implicit).
|
||||||
#SSO_SCOPES="email profile"
|
#SSO_SCOPES="email profile"
|
||||||
|
|
||||||
## Additionnal authorization url parameters (ex: to obtain a `refresh_token` with Google Auth).
|
## Additionnal authorization url parameters (ex: to obtain a `refresh_token` with Google Auth).
|
||||||
# SSO_AUTHORIZE_EXTRA_PARAMS="access_type=offline&prompt=consent"
|
# SSO_AUTHORIZE_EXTRA_PARAMS="access_type=offline&prompt=consent"
|
||||||
|
|
||||||
## Activate PKCE for the Auth Code flow.
|
## Activate PKCE for the Auth Code flow.
|
||||||
# SSO_PKCE=true
|
# SSO_PKCE=true
|
||||||
|
|
||||||
## Regex to add additionnal trusted audience to Id Token (by default only the client_id is trusted).
|
## Regex to add additionnal trusted audience to Id Token (by default only the client_id is trusted).
|
||||||
# SSO_AUDIENCE_TRUSTED='^$'
|
# SSO_AUDIENCE_TRUSTED='^$'
|
||||||
|
|
||||||
## Set your Client ID and Client Key
|
## Set your Client ID and Client Key
|
||||||
# SSO_CLIENT_ID=11111
|
# SSO_CLIENT_ID=11111
|
||||||
# SSO_CLIENT_SECRET=AAAAAAAAAAAAAAAAAAAAAAAA
|
# SSO_CLIENT_SECRET=AAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
|
||||||
## Optional Master password policy (minComplexity=[0-4]), `enforceOnLogin` is not supported at the moment.
|
## Optional Master password policy (minComplexity=[0-4]), `enforceOnLogin` is not supported at the moment.
|
||||||
# SSO_MASTER_PASSWORD_POLICY='{"enforceOnLogin":false,"minComplexity":3,"minLength":12,"requireLower":false,"requireNumbers":false,"requireSpecial":false,"requireUpper":false}'
|
# SSO_MASTER_PASSWORD_POLICY='{"enforceOnLogin":false,"minComplexity":3,"minLength":12,"requireLower":false,"requireNumbers":false,"requireSpecial":false,"requireUpper":false}'
|
||||||
|
|
||||||
## Use sso only for authentication not the session lifecycle
|
## Use sso only for authentication not the session lifecycle
|
||||||
# SSO_AUTH_ONLY_NOT_SESSION=false
|
# SSO_AUTH_ONLY_NOT_SESSION=false
|
||||||
|
|
||||||
## Client cache for discovery endpoint. Duration in seconds (0 to disable).
|
## Client cache for discovery endpoint. Duration in seconds (0 to disable).
|
||||||
# SSO_CLIENT_CACHE_EXPIRATION=0
|
# SSO_CLIENT_CACHE_EXPIRATION=0
|
||||||
|
|
||||||
## Log all the tokens, LOG_LEVEL=debug is required
|
## Log all the tokens, LOG_LEVEL=debug is required
|
||||||
# SSO_DEBUG_TOKENS=false
|
# SSO_DEBUG_TOKENS=false
|
||||||
|
|
||||||
|
|
21
SSO.md
21
SSO.md
|
@ -47,7 +47,7 @@ Additionally:
|
||||||
- Signup will be blocked if the Provider reports the email as `unverified`.
|
- Signup will be blocked if the Provider reports the email as `unverified`.
|
||||||
- Changing the email needs to be done by the user since it requires updating the `key`.
|
- Changing the email needs to be done by the user since it requires updating the `key`.
|
||||||
On login if the email returned by the provider is not the one saved an email will be sent to the user to ask him to update it.
|
On login if the email returned by the provider is not the one saved an email will be sent to the user to ask him to update it.
|
||||||
- If set `SIGNUPS_DOMAINS_WHITELIST` is applied on SSO signup and when attempting to change the email.
|
- If set, `SIGNUPS_DOMAINS_WHITELIST` is applied on SSO signup and when attempting to change the email.
|
||||||
|
|
||||||
This means that if you ever need to change the provider url or the provider itself; you'll have to first delete the association
|
This means that if you ever need to change the provider url or the provider itself; you'll have to first delete the association
|
||||||
then ensure that `SSO_SIGNUPS_MATCH_EMAIL` is activated to allow a new association.
|
then ensure that `SSO_SIGNUPS_MATCH_EMAIL` is activated to allow a new association.
|
||||||
|
@ -118,22 +118,7 @@ More details on how to use it in [README.md](playwright/README.md#openid-connect
|
||||||
## Auth0
|
## Auth0
|
||||||
|
|
||||||
Not working due to the following issue https://github.com/ramosbugs/openidconnect-rs/issues/23 (they appear not to follow the spec).
|
Not working due to the following issue https://github.com/ramosbugs/openidconnect-rs/issues/23 (they appear not to follow the spec).
|
||||||
A feature flag is available to bypass the issue but since it's a compile time feature you will have to patch with something like:
|
A feature flag is available (`oidc-accept-rfc3339-timestamps`) to bypass the issue but you will need to compile the server with it.
|
||||||
|
|
||||||
```patch
|
|
||||||
diff --git a/Cargo.toml b/Cargo.toml
|
|
||||||
index 0524a7be..9999e852 100644
|
|
||||||
--- a/Cargo.toml
|
|
||||||
+++ b/Cargo.toml
|
|
||||||
@@ -150,7 +150,7 @@ paste = "1.0.15"
|
|
||||||
governor = "0.6.3"
|
|
||||||
|
|
||||||
# OIDC for SSO
|
|
||||||
-openidconnect = "3.5.0"
|
|
||||||
+openidconnect = { version = "3.5.0", features = ["accept-rfc3339-timestamps"] }
|
|
||||||
mini-moka = "0.10.2"
|
|
||||||
```
|
|
||||||
|
|
||||||
There is no plan at the moment to either always activate the feature nor make a specific distribution for Auth0.
|
There is no plan at the moment to either always activate the feature nor make a specific distribution for Auth0.
|
||||||
|
|
||||||
## Authelia
|
## Authelia
|
||||||
|
@ -291,7 +276,7 @@ There is some issue to handle redirection from your browser (used for sso login)
|
||||||
|
|
||||||
### Chrome
|
### Chrome
|
||||||
|
|
||||||
Probably not much hope, an [issue](https://github.com/bitwarden/clients/issues/2606) is open on the subject and it appears that both Linux and Windows are not working.
|
Some user report having ([issues](https://github.com/bitwarden/clients/issues/12929)).
|
||||||
|
|
||||||
## Firefox
|
## Firefox
|
||||||
|
|
||||||
|
|
|
@ -1211,7 +1211,7 @@ struct SecretVerificationRequest {
|
||||||
|
|
||||||
// Change the KDF Iterations if necessary
|
// Change the KDF Iterations if necessary
|
||||||
pub async fn kdf_upgrade(user: &mut User, pwd_hash: &str, conn: &mut DbConn) -> ApiResult<()> {
|
pub async fn kdf_upgrade(user: &mut User, pwd_hash: &str, conn: &mut DbConn) -> ApiResult<()> {
|
||||||
if user.password_iterations != CONFIG.password_iterations() {
|
if user.password_iterations < CONFIG.password_iterations() {
|
||||||
user.password_iterations = CONFIG.password_iterations();
|
user.password_iterations = CONFIG.password_iterations();
|
||||||
user.set_password(pwd_hash, None, false, None);
|
user.set_password(pwd_hash, None, false, None);
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ pub fn routes() -> Vec<Route> {
|
||||||
identity_register,
|
identity_register,
|
||||||
register_verification_email,
|
register_verification_email,
|
||||||
register_finish,
|
register_finish,
|
||||||
_prevalidate,
|
|
||||||
prevalidate,
|
prevalidate,
|
||||||
authorize,
|
authorize,
|
||||||
oidcsignin,
|
oidcsignin,
|
||||||
|
@ -990,7 +989,7 @@ struct ConnectData {
|
||||||
#[field(name = uncased("authrequest"))]
|
#[field(name = uncased("authrequest"))]
|
||||||
auth_request: Option<AuthRequestId>,
|
auth_request: Option<AuthRequestId>,
|
||||||
// Needed for authorization code
|
// Needed for authorization code
|
||||||
#[form(field = uncased("code"))]
|
#[field(name = uncased("code"))]
|
||||||
code: Option<String>,
|
code: Option<String>,
|
||||||
}
|
}
|
||||||
fn _check_is_some<T>(value: &Option<T>, msg: &str) -> EmptyResult {
|
fn _check_is_some<T>(value: &Option<T>, msg: &str) -> EmptyResult {
|
||||||
|
@ -1000,12 +999,6 @@ fn _check_is_some<T>(value: &Option<T>, msg: &str) -> EmptyResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated but still needed for Mobile apps
|
|
||||||
#[get("/account/prevalidate")]
|
|
||||||
fn _prevalidate() -> JsonResult {
|
|
||||||
prevalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/sso/prevalidate")]
|
#[get("/sso/prevalidate")]
|
||||||
fn prevalidate() -> JsonResult {
|
fn prevalidate() -> JsonResult {
|
||||||
if CONFIG.sso_enabled() {
|
if CONFIG.sso_enabled() {
|
||||||
|
@ -1032,7 +1025,7 @@ async fn oidcsignin(code: OIDCCode, state: String, conn: DbConn) -> ApiResult<Re
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bitwarden client appear to only care for code and state so we pipe it through
|
// Bitwarden client appear to only care for code and state so we pipe it through
|
||||||
// cf: https://github.com/bitwarden/clients/blob/8e46ef1ae5be8b62b0d3d0b9d1b1c62088a04638/libs/angular/src/auth/components/sso.component.ts#L68C11-L68C23)
|
// cf: https://github.com/bitwarden/clients/blob/80b74b3300e15b4ae414dc06044cc9b02b6c10a6/libs/auth/src/angular/sso/sso.component.ts#L141
|
||||||
#[get("/connect/oidc-signin?<state>&<error>&<error_description>", rank = 2)]
|
#[get("/connect/oidc-signin?<state>&<error>&<error_description>", rank = 2)]
|
||||||
async fn oidcsignin_error(
|
async fn oidcsignin_error(
|
||||||
state: String,
|
state: String,
|
||||||
|
|
111
src/config.rs
111
src/config.rs
|
@ -458,7 +458,7 @@ make_config! {
|
||||||
/// Duo Auth context cleanup schedule |> Cron schedule of the job that cleans expired Duo contexts from the database. Does nothing if Duo MFA is disabled or set to use the legacy iframe prompt.
|
/// Duo Auth context cleanup schedule |> Cron schedule of the job that cleans expired Duo contexts from the database. Does nothing if Duo MFA is disabled or set to use the legacy iframe prompt.
|
||||||
/// Defaults to once every minute. Set blank to disable this job.
|
/// Defaults to once every minute. Set blank to disable this job.
|
||||||
duo_context_purge_schedule: String, false, def, "30 * * * * *".to_string();
|
duo_context_purge_schedule: String, false, def, "30 * * * * *".to_string();
|
||||||
/// Purge incomplete sso nonce. |> Cron schedule of the job that cleans leftover nonce in db due to incomplete sso login.
|
/// Purge incomplete SSO nonce. |> Cron schedule of the job that cleans leftover nonce in db due to incomplete SSO login.
|
||||||
/// Defaults to daily. Set blank to disable this job.
|
/// Defaults to daily. Set blank to disable this job.
|
||||||
purge_incomplete_sso_nonce: String, false, def, "0 20 0 * * *".to_string();
|
purge_incomplete_sso_nonce: String, false, def, "0 20 0 * * *".to_string();
|
||||||
},
|
},
|
||||||
|
@ -682,10 +682,10 @@ make_config! {
|
||||||
/// OpenID Connect SSO settings
|
/// OpenID Connect SSO settings
|
||||||
sso {
|
sso {
|
||||||
/// Enabled
|
/// Enabled
|
||||||
sso_enabled: bool, false, def, false;
|
sso_enabled: bool, true, def, false;
|
||||||
/// Only sso login |> Disable Email+Master Password login
|
/// Only SSO login |> Disable Email+Master Password login
|
||||||
sso_only: bool, true, def, false;
|
sso_only: bool, true, def, false;
|
||||||
/// Allow email association |> Associate existing non-sso user based on email
|
/// Allow email association |> Associate existing non-SSO user based on email
|
||||||
sso_signups_match_email: bool, true, def, true;
|
sso_signups_match_email: bool, true, def, true;
|
||||||
/// Allow unknown email verification status |> Allowing this with `SSO_SIGNUPS_MATCH_EMAIL=true` open potential account takeover.
|
/// Allow unknown email verification status |> Allowing this with `SSO_SIGNUPS_MATCH_EMAIL=true` open potential account takeover.
|
||||||
sso_allow_unknown_email_verification: bool, false, def, false;
|
sso_allow_unknown_email_verification: bool, false, def, false;
|
||||||
|
@ -701,13 +701,13 @@ make_config! {
|
||||||
sso_authorize_extra_params: String, false, def, String::new();
|
sso_authorize_extra_params: String, false, def, String::new();
|
||||||
/// Use PKCE during Authorization flow
|
/// Use PKCE during Authorization flow
|
||||||
sso_pkce: bool, false, def, true;
|
sso_pkce: bool, false, def, true;
|
||||||
/// Regex for additionnal trusted Id token audience |> By default only the client_id is trsuted.
|
/// Regex for additionnal trusted Id token audience |> By default only the client_id is trusted.
|
||||||
sso_audience_trusted: String, false, option;
|
sso_audience_trusted: String, false, option;
|
||||||
/// CallBack Path |> Generated from Domain.
|
/// CallBack Path |> Generated from Domain.
|
||||||
sso_callback_path: String, false, generated, |c| generate_sso_callback_path(&c.domain);
|
sso_callback_path: String, false, generated, |c| generate_sso_callback_path(&c.domain);
|
||||||
/// Optional sso master password policy |> Ex format: '{"enforceOnLogin":false,"minComplexity":3,"minLength":12,"requireLower":false,"requireNumbers":false,"requireSpecial":false,"requireUpper":false}'
|
/// Optional SSO master password policy |> Ex format: '{"enforceOnLogin":false,"minComplexity":3,"minLength":12,"requireLower":false,"requireNumbers":false,"requireSpecial":false,"requireUpper":false}'
|
||||||
sso_master_password_policy: String, true, option;
|
sso_master_password_policy: String, true, option;
|
||||||
/// Use sso only for auth not the session lifecycle |> Use default Vaultwarden session lifecycle (Idle refresh token valid for 30days)
|
/// Use SSO only for auth not the session lifecycle |> Use default Vaultwarden session lifecycle (Idle refresh token valid for 30days)
|
||||||
sso_auth_only_not_session: bool, true, def, false;
|
sso_auth_only_not_session: bool, true, def, false;
|
||||||
/// Client cache for discovery endpoint. |> Duration in seconds (0 or less to disable). More details: https://github.com/dani-garcia/vaultwarden/blob/sso-support/SSO.md#client-cache
|
/// Client cache for discovery endpoint. |> Duration in seconds (0 or less to disable). More details: https://github.com/dani-garcia/vaultwarden/blob/sso-support/SSO.md#client-cache
|
||||||
sso_client_cache_expiration: u64, true, def, 0;
|
sso_client_cache_expiration: u64, true, def, 0;
|
||||||
|
@ -955,10 +955,9 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> {
|
||||||
err!("`SSO_CLIENT_ID`, `SSO_CLIENT_SECRET` and `SSO_AUTHORITY` must be set for SSO support")
|
err!("`SSO_CLIENT_ID`, `SSO_CLIENT_SECRET` and `SSO_AUTHORITY` must be set for SSO support")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal_sso_issuer_url(&cfg.sso_authority)?;
|
validate_internal_sso_issuer_url(&cfg.sso_authority)?;
|
||||||
internal_sso_redirect_url(&cfg.sso_callback_path)?;
|
validate_internal_sso_redirect_url(&cfg.sso_callback_path)?;
|
||||||
check_master_password_policy(&cfg.sso_master_password_policy)?;
|
check_master_password_policy(&cfg.sso_master_password_policy)?;
|
||||||
internal_sso_authorize_extra_params_vec(&cfg.sso_authorize_extra_params)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg._enable_yubico {
|
if cfg._enable_yubico {
|
||||||
|
@ -1138,27 +1137,20 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_sso_issuer_url(sso_authority: &String) -> Result<openidconnect::IssuerUrl, Error> {
|
fn validate_internal_sso_issuer_url(sso_authority: &String) -> Result<openidconnect::IssuerUrl, Error> {
|
||||||
match openidconnect::IssuerUrl::new(sso_authority.clone()) {
|
match openidconnect::IssuerUrl::new(sso_authority.clone()) {
|
||||||
Err(err) => err!(format!("Invalid sso_authority UR ({sso_authority}): {err}")),
|
Err(err) => err!(format!("Invalid sso_authority UR ({sso_authority}): {err}")),
|
||||||
Ok(issuer_url) => Ok(issuer_url),
|
Ok(issuer_url) => Ok(issuer_url),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_sso_redirect_url(sso_callback_path: &String) -> Result<openidconnect::RedirectUrl, Error> {
|
fn validate_internal_sso_redirect_url(sso_callback_path: &String) -> Result<openidconnect::RedirectUrl, Error> {
|
||||||
match openidconnect::RedirectUrl::new(sso_callback_path.clone()) {
|
match openidconnect::RedirectUrl::new(sso_callback_path.clone()) {
|
||||||
Err(err) => err!(format!("Invalid sso_callback_path ({sso_callback_path} built using `domain`) URL: {err}")),
|
Err(err) => err!(format!("Invalid sso_callback_path ({sso_callback_path} built using `domain`) URL: {err}")),
|
||||||
Ok(redirect_url) => Ok(redirect_url),
|
Ok(redirect_url) => Ok(redirect_url),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_sso_authorize_extra_params_vec(config: &str) -> Result<Vec<(String, String)>, Error> {
|
|
||||||
match parse_param_list(config.to_owned(), '&', '=') {
|
|
||||||
Err(e) => err!(format!("Invalid SSO_AUTHORIZE_EXTRA_PARAMS: {e}")),
|
|
||||||
Ok(params) => Ok(params),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_master_password_policy(sso_master_password_policy: &Option<String>) -> Result<(), Error> {
|
fn check_master_password_policy(sso_master_password_policy: &Option<String>) -> Result<(), Error> {
|
||||||
let policy = sso_master_password_policy.as_ref().map(|mpp| serde_json::from_str::<serde_json::Value>(mpp));
|
let policy = sso_master_password_policy.as_ref().map(|mpp| serde_json::from_str::<serde_json::Value>(mpp));
|
||||||
if let Some(Err(error)) = policy {
|
if let Some(Err(error)) = policy {
|
||||||
|
@ -1244,26 +1236,6 @@ fn smtp_convert_deprecated_ssl_options(smtp_ssl: Option<bool>, smtp_explicit_tls
|
||||||
"starttls".to_string()
|
"starttls".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allow to parse a list of Key/Values (Ex: `key1=value&key2=value2`)
|
|
||||||
/// - line break are handled as `separator`
|
|
||||||
fn parse_param_list(config: String, separator: char, kv_separator: char) -> Result<Vec<(String, String)>, Error> {
|
|
||||||
config
|
|
||||||
.lines()
|
|
||||||
.flat_map(|l| l.split(separator))
|
|
||||||
.map(|l| l.trim())
|
|
||||||
.filter(|l| !l.is_empty())
|
|
||||||
.map(|l| {
|
|
||||||
let split = l.split(kv_separator).collect::<Vec<&str>>();
|
|
||||||
match &split[..] {
|
|
||||||
[key, value] => Ok(((*key).to_string(), (*value).to_string())),
|
|
||||||
_ => {
|
|
||||||
err!(format!("Failed to parse ({l}). Expected key{kv_separator}value"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opendal_operator_for_path(path: &str) -> Result<opendal::Operator, Error> {
|
fn opendal_operator_for_path(path: &str) -> Result<opendal::Operator, Error> {
|
||||||
// Cache of previously built operators by path
|
// Cache of previously built operators by path
|
||||||
static OPERATORS_BY_PATH: LazyLock<dashmap::DashMap<String, opendal::Operator>> =
|
static OPERATORS_BY_PATH: LazyLock<dashmap::DashMap<String, opendal::Operator>> =
|
||||||
|
@ -1459,7 +1431,7 @@ impl Config {
|
||||||
|
|
||||||
// The registration link should be hidden if
|
// The registration link should be hidden if
|
||||||
// - Signup is not allowed and email whitelist is empty unless mail is disabled and invitations are allowed
|
// - Signup is not allowed and email whitelist is empty unless mail is disabled and invitations are allowed
|
||||||
// - The sso is activated and password login is disabled.
|
// - The SSO is activated and password login is disabled.
|
||||||
pub fn is_signup_disabled(&self) -> bool {
|
pub fn is_signup_disabled(&self) -> bool {
|
||||||
(!self.signups_allowed()
|
(!self.signups_allowed()
|
||||||
&& self.signups_domains_whitelist().is_empty()
|
&& self.signups_domains_whitelist().is_empty()
|
||||||
|
@ -1582,19 +1554,19 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sso_issuer_url(&self) -> Result<openidconnect::IssuerUrl, Error> {
|
pub fn sso_issuer_url(&self) -> Result<openidconnect::IssuerUrl, Error> {
|
||||||
internal_sso_issuer_url(&self.sso_authority())
|
validate_internal_sso_issuer_url(&self.sso_authority())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sso_redirect_url(&self) -> Result<openidconnect::RedirectUrl, Error> {
|
pub fn sso_redirect_url(&self) -> Result<openidconnect::RedirectUrl, Error> {
|
||||||
internal_sso_redirect_url(&self.sso_callback_path())
|
validate_internal_sso_redirect_url(&self.sso_callback_path())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sso_scopes_vec(&self) -> Vec<String> {
|
pub fn sso_scopes_vec(&self) -> Vec<String> {
|
||||||
self.sso_scopes().split_whitespace().map(str::to_string).collect()
|
self.sso_scopes().split_whitespace().map(str::to_string).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sso_authorize_extra_params_vec(&self) -> Result<Vec<(String, String)>, Error> {
|
pub fn sso_authorize_extra_params_vec(&self) -> Vec<(String, String)> {
|
||||||
internal_sso_authorize_extra_params_vec(&self.sso_authorize_extra_params())
|
url::form_urlencoded::parse(self.sso_authorize_extra_params().as_bytes()).into_owned().collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1760,54 +1732,3 @@ handlebars::handlebars_helper!(webver: | web_vault_version: String |
|
||||||
handlebars::handlebars_helper!(vwver: | vw_version: String |
|
handlebars::handlebars_helper!(vwver: | vw_version: String |
|
||||||
semver::VersionReq::parse(&vw_version).expect("Invalid Vaultwarden version compare string").matches(&VW_VERSION)
|
semver::VersionReq::parse(&vw_version).expect("Invalid Vaultwarden version compare string").matches(&VW_VERSION)
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_param_list() {
|
|
||||||
let config = "key1=value&key2=value2&".to_string();
|
|
||||||
let parsed = parse_param_list(config, '&', '=');
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
parsed.unwrap(),
|
|
||||||
vec![("key1".to_string(), "value".to_string()), ("key2".to_string(), "value2".to_string())]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_param_list_lines() {
|
|
||||||
let config = r#"
|
|
||||||
key1=value
|
|
||||||
key2=value2
|
|
||||||
"#
|
|
||||||
.to_string();
|
|
||||||
let parsed = parse_param_list(config, '&', '=');
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
parsed.unwrap(),
|
|
||||||
vec![("key1".to_string(), "value".to_string()), ("key2".to_string(), "value2".to_string())]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_param_list_mixed() {
|
|
||||||
let config = r#"key1=value&key2=value2&
|
|
||||||
&key3=value3&&
|
|
||||||
&key4=value4
|
|
||||||
"#
|
|
||||||
.to_string();
|
|
||||||
let parsed = parse_param_list(config, '&', '=');
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
parsed.unwrap(),
|
|
||||||
vec![
|
|
||||||
("key1".to_string(), "value".to_string()),
|
|
||||||
("key2".to_string(), "value2".to_string()),
|
|
||||||
("key3".to_string(), "value3".to_string()),
|
|
||||||
("key4".to_string(), "value4".to_string()),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ pub enum EventType {
|
||||||
OrganizationUserUpdated = 1502,
|
OrganizationUserUpdated = 1502,
|
||||||
OrganizationUserRemoved = 1503, // Organization user data was deleted
|
OrganizationUserRemoved = 1503, // Organization user data was deleted
|
||||||
OrganizationUserUpdatedGroups = 1504,
|
OrganizationUserUpdatedGroups = 1504,
|
||||||
OrganizationUserUnlinkedSso = 1505, // Not supported
|
OrganizationUserUnlinkedSso = 1505,
|
||||||
OrganizationUserResetPasswordEnroll = 1506,
|
OrganizationUserResetPasswordEnroll = 1506,
|
||||||
OrganizationUserResetPasswordWithdraw = 1507,
|
OrganizationUserResetPasswordWithdraw = 1507,
|
||||||
OrganizationUserAdminResetPassword = 1508,
|
OrganizationUserAdminResetPassword = 1508,
|
||||||
|
|
|
@ -124,7 +124,7 @@ impl Client {
|
||||||
Nonce::new_random,
|
Nonce::new_random,
|
||||||
)
|
)
|
||||||
.add_scopes(scopes)
|
.add_scopes(scopes)
|
||||||
.add_extra_params(CONFIG.sso_authorize_extra_params_vec()?);
|
.add_extra_params(CONFIG.sso_authorize_extra_params_vec());
|
||||||
|
|
||||||
let verifier = if CONFIG.sso_pkce() {
|
let verifier = if CONFIG.sso_pkce() {
|
||||||
let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
|
let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue