mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-07-31 08:09:07 +00:00
Add SSO functionality using OpenID Connect
Co-authored-by: Pablo Ovelleiro Corral <mail@pablo.tools> Co-authored-by: Stuart Heap <sheap13@gmail.com> Co-authored-by: Alex Moore <skiepp@my-dockerfarm.cloud> Co-authored-by: Brian Munro <brian.alexander.munro@gmail.com> Co-authored-by: Jacques B. <timshel@github.com>
This commit is contained in:
parent
10d12676cf
commit
671f7a1d31
24 changed files with 700 additions and 13 deletions
|
@ -33,6 +33,7 @@ pub fn routes() -> Vec<rocket::Route> {
|
|||
get_public_keys,
|
||||
post_keys,
|
||||
post_password,
|
||||
post_set_password,
|
||||
post_kdf,
|
||||
post_rotatekey,
|
||||
post_sstamp,
|
||||
|
@ -82,6 +83,21 @@ pub struct RegisterData {
|
|||
organization_user_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetPasswordData {
|
||||
kdf: Option<i32>,
|
||||
kdf_iterations: Option<i32>,
|
||||
kdf_memory: Option<i32>,
|
||||
kdf_parallelism: Option<i32>,
|
||||
key: String,
|
||||
keys: Option<KeysData>,
|
||||
master_password_hash: String,
|
||||
master_password_hint: Option<String>,
|
||||
#[allow(dead_code)]
|
||||
org_identifier: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct KeysData {
|
||||
|
@ -89,6 +105,13 @@ struct KeysData {
|
|||
public_key: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct TokenPayload {
|
||||
exp: i64,
|
||||
email: String,
|
||||
nonce: String,
|
||||
}
|
||||
|
||||
/// Trims whitespace from password hints, and converts blank password hints to `None`.
|
||||
fn clean_password_hint(password_hint: &Option<String>) -> Option<String> {
|
||||
match password_hint {
|
||||
|
@ -244,6 +267,50 @@ pub async fn _register(data: Json<RegisterData>, mut conn: DbConn) -> JsonResult
|
|||
})))
|
||||
}
|
||||
|
||||
#[post("/accounts/set-password", data = "<data>")]
|
||||
async fn post_set_password(data: Json<SetPasswordData>, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
let data: SetPasswordData = data.into_inner();
|
||||
let mut user = headers.user;
|
||||
|
||||
// Check against the password hint setting here so if it fails, the user
|
||||
// can retry without losing their invitation below.
|
||||
let password_hint = clean_password_hint(&data.master_password_hash);
|
||||
enforce_password_hint_setting(&password_hint)?;
|
||||
|
||||
if let Some(client_kdf_iter) = data.kdf_iterations {
|
||||
user.client_kdf_iter = client_kdf_iter;
|
||||
}
|
||||
|
||||
if let Some(client_kdf_type) = data.kdf {
|
||||
user.client_kdf_type = client_kdf_type;
|
||||
}
|
||||
|
||||
// We need to allow revision-date to use the old security_timestamp
|
||||
let routes = ["revision_date"];
|
||||
let routes: Option<Vec<String>> = Some(routes.iter().map(ToString::to_string).collect());
|
||||
|
||||
user.client_kdf_memory = data.kdf_memory;
|
||||
user.client_kdf_parallelism = data.kdf_parallelism;
|
||||
|
||||
user.set_password(&data.master_password_hash, Some(data.key), false, routes);
|
||||
user.password_hint = password_hint;
|
||||
|
||||
if let Some(keys) = data.keys {
|
||||
user.private_key = Some(keys.encrypted_private_key);
|
||||
user.public_key = Some(keys.public_key);
|
||||
}
|
||||
|
||||
if CONFIG.mail_enabled() {
|
||||
mail::send_set_password(&user.email.to_lowercase(), &user.name).await?;
|
||||
}
|
||||
|
||||
user.save(&mut conn).await?;
|
||||
Ok(Json(json!({
|
||||
"Object": "set-password",
|
||||
"CaptchaBypassToken": "",
|
||||
})))
|
||||
}
|
||||
|
||||
#[get("/accounts/profile")]
|
||||
async fn profile(headers: Headers, mut conn: DbConn) -> Json<Value> {
|
||||
Json(headers.user.to_json(&mut conn).await)
|
||||
|
@ -980,7 +1047,7 @@ struct SecretVerificationRequest {
|
|||
}
|
||||
|
||||
#[post("/accounts/verify-password", data = "<data>")]
|
||||
fn verify_password(data: Json<SecretVerificationRequest>, headers: Headers) -> EmptyResult {
|
||||
fn verify_password(data: Json<SecretVerificationRequest>, headers: Headers) -> JsonResult {
|
||||
let data: SecretVerificationRequest = data.into_inner();
|
||||
let user = headers.user;
|
||||
|
||||
|
@ -988,7 +1055,9 @@ fn verify_password(data: Json<SecretVerificationRequest>, headers: Headers) -> E
|
|||
err!("Invalid password")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(Json(json!({
|
||||
"MasterPasswordPolicy": {}, // Required for SSO login with mobile apps
|
||||
})))
|
||||
}
|
||||
|
||||
async fn _api_key(data: Json<PasswordOrOtpData>, rotate: bool, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue