You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
3.6 KiB
117 lines
3.6 KiB
use rocket::Route;
|
|
use rocket::serde::json::Json;
|
|
use serde_json::Value;
|
|
|
|
use crate::{
|
|
CONFIG,
|
|
api::{EmptyResult, JsonResult},
|
|
auth::Headers,
|
|
db::{
|
|
DbConn,
|
|
models::{Membership, MembershipType, UserId},
|
|
},
|
|
};
|
|
|
|
pub fn routes() -> Vec<Route> {
|
|
routes![post_set_key_connector_key, post_convert_to_key_connector, get_confirmation_details,]
|
|
}
|
|
|
|
#[derive(Debug, serde::Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct KeyPairData {
|
|
encrypted_private_key: String,
|
|
public_key: String,
|
|
}
|
|
|
|
#[derive(Debug, serde::Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SetKeyConnectorKeyData {
|
|
key: String,
|
|
keys: KeyPairData,
|
|
kdf: i32,
|
|
kdf_iterations: i32,
|
|
kdf_memory: Option<i32>,
|
|
kdf_parallelism: Option<i32>,
|
|
#[allow(dead_code)]
|
|
org_identifier: String,
|
|
}
|
|
|
|
async fn can_use_key_connector(user_uuid: &UserId, conn: &DbConn) -> EmptyResult {
|
|
if Membership::find_by_user(user_uuid, conn).await.iter().any(|m| m.atype >= MembershipType::Admin) {
|
|
err!("Owners and admins cannot use Key Connector and must keep a master password");
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
// Called by the client to finish provisioning a new SSO user whose master key
|
|
// was just stored on the key connector.
|
|
#[post("/accounts/set-key-connector-key", data = "<data>")]
|
|
async fn post_set_key_connector_key(data: Json<SetKeyConnectorKeyData>, headers: Headers, conn: DbConn) -> EmptyResult {
|
|
if !CONFIG.key_connector_enabled() {
|
|
err!("Key Connector is not enabled on this server");
|
|
}
|
|
|
|
let data = data.into_inner();
|
|
let mut user = headers.user;
|
|
|
|
if user.private_key.is_some() {
|
|
err!("Account already initialized, cannot set Key Connector key");
|
|
}
|
|
|
|
can_use_key_connector(&user.uuid, &conn).await?;
|
|
|
|
user.client_kdf_type = data.kdf;
|
|
user.client_kdf_iter = data.kdf_iterations;
|
|
user.client_kdf_memory = data.kdf_memory;
|
|
user.client_kdf_parallelism = data.kdf_parallelism;
|
|
|
|
user.akey = data.key;
|
|
user.private_key = Some(data.keys.encrypted_private_key);
|
|
user.public_key = Some(data.keys.public_key);
|
|
|
|
// Key connector users don't have a master password
|
|
user.password_hash = Vec::new();
|
|
user.uses_key_connector = true;
|
|
|
|
user.save(&conn).await
|
|
}
|
|
|
|
// Migrates an existing password user to the key connector. The client has already
|
|
// uploaded the current master key to the connector at this point.
|
|
#[post("/accounts/convert-to-key-connector")]
|
|
async fn post_convert_to_key_connector(headers: Headers, conn: DbConn) -> EmptyResult {
|
|
if !CONFIG.key_connector_enabled() {
|
|
err!("Key Connector is not enabled on this server");
|
|
}
|
|
|
|
let mut user = headers.user;
|
|
|
|
if user.private_key.is_none() {
|
|
err!("Account is not initialized, cannot convert to Key Connector");
|
|
}
|
|
|
|
can_use_key_connector(&user.uuid, &conn).await?;
|
|
|
|
user.password_hash = Vec::new();
|
|
user.password_hint = None;
|
|
user.uses_key_connector = true;
|
|
|
|
user.save(&conn).await
|
|
}
|
|
|
|
#[get("/accounts/key-connector/confirmation-details/<_org_identifier>")]
|
|
fn get_confirmation_details(_org_identifier: &str, _headers: Headers) -> JsonResult {
|
|
if !CONFIG.key_connector_enabled() {
|
|
err!("Key Connector is not enabled on this server");
|
|
}
|
|
|
|
// SSO (and therefore the key connector) is global, so there is no real org to look up
|
|
Ok(Json(serde_json::json!({
|
|
"OrganizationName": CONFIG.key_connector_org_name(),
|
|
"Object": "keyConnectorUserDecryptionOptionConfirmationDetails"
|
|
})))
|
|
}
|
|
|
|
pub fn key_connector_user_decryption_option() -> Value {
|
|
serde_json::json!({ "KeyConnectorUrl": CONFIG.key_connector_url() })
|
|
}
|
|
|