mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-07-20 19:18:21 +00:00
Add support for Organization token
This is a WIP for adding organization token login support. It has basic token login and verification support, but that's about it. This branch is a refresh of the previous version, and will contain code from a PR based upon my previous branch.
This commit is contained in:
parent
bd883de70e
commit
4219249e11
15 changed files with 272 additions and 18 deletions
|
@ -1,6 +1,6 @@
|
|||
use chrono::{NaiveDateTime, Utc};
|
||||
|
||||
use crate::CONFIG;
|
||||
use crate::{crypto, CONFIG};
|
||||
|
||||
db_object! {
|
||||
#[derive(Identifiable, Queryable, Insertable, AsChangeset)]
|
||||
|
@ -47,9 +47,7 @@ impl Device {
|
|||
}
|
||||
|
||||
pub fn refresh_twofactor_remember(&mut self) -> String {
|
||||
use crate::crypto;
|
||||
use data_encoding::BASE64;
|
||||
|
||||
let twofactor_remember = crypto::encode_random_bytes::<180>(BASE64);
|
||||
self.twofactor_remember = Some(twofactor_remember.clone());
|
||||
|
||||
|
@ -68,9 +66,7 @@ impl Device {
|
|||
) -> (String, i64) {
|
||||
// If there is no refresh token, we create one
|
||||
if self.refresh_token.is_empty() {
|
||||
use crate::crypto;
|
||||
use data_encoding::BASE64URL;
|
||||
|
||||
self.refresh_token = crypto::encode_random_bytes::<64>(BASE64URL);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ pub use self::favorite::Favorite;
|
|||
pub use self::folder::{Folder, FolderCipher};
|
||||
pub use self::group::{CollectionGroup, Group, GroupUser};
|
||||
pub use self::org_policy::{OrgPolicy, OrgPolicyErr, OrgPolicyType};
|
||||
pub use self::organization::{Organization, UserOrgStatus, UserOrgType, UserOrganization};
|
||||
pub use self::organization::{Organization, OrganizationApiKey, UserOrgStatus, UserOrgType, UserOrganization};
|
||||
pub use self::send::{Send, SendType};
|
||||
pub use self::two_factor::{TwoFactor, TwoFactorType};
|
||||
pub use self::two_factor_incomplete::TwoFactorIncomplete;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use chrono::{NaiveDateTime, Utc};
|
||||
use num_traits::FromPrimitive;
|
||||
use serde_json::Value;
|
||||
use std::cmp::Ordering;
|
||||
|
@ -31,6 +32,17 @@ db_object! {
|
|||
pub atype: i32,
|
||||
pub reset_password_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Identifiable, Queryable, Insertable, AsChangeset)]
|
||||
#[diesel(table_name = organization_api_key)]
|
||||
#[diesel(primary_key(uuid, org_uuid))]
|
||||
pub struct OrganizationApiKey {
|
||||
pub uuid: String,
|
||||
pub org_uuid: String,
|
||||
pub atype: i32,
|
||||
pub api_key: String,
|
||||
pub revision_date: NaiveDateTime,
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/bitwarden/server/blob/b86a04cef9f1e1b82cf18e49fc94e017c641130c/src/Core/Enums/OrganizationUserStatusType.cs
|
||||
|
@ -157,7 +169,7 @@ impl Organization {
|
|||
"UseSso": false, // Not supported
|
||||
// "UseKeyConnector": false, // Not supported
|
||||
"SelfHost": true,
|
||||
"UseApi": false, // Not supported
|
||||
"UseApi": true,
|
||||
"HasPublicAndPrivateKeys": self.private_key.is_some() && self.public_key.is_some(),
|
||||
"UseResetPassword": CONFIG.mail_enabled(),
|
||||
|
||||
|
@ -212,6 +224,23 @@ impl UserOrganization {
|
|||
}
|
||||
}
|
||||
|
||||
impl OrganizationApiKey {
|
||||
pub fn new(org_uuid: String, api_key: String) -> Self {
|
||||
Self {
|
||||
uuid: crate::util::get_uuid(),
|
||||
|
||||
org_uuid,
|
||||
atype: 0, // Type 0 is the default and only type we support currently
|
||||
api_key,
|
||||
revision_date: Utc::now().naive_utc(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_valid_api_key(&self, api_key: &str) -> bool {
|
||||
crate::crypto::ct_eq(&self.api_key, api_key)
|
||||
}
|
||||
}
|
||||
|
||||
use crate::db::DbConn;
|
||||
|
||||
use crate::api::EmptyResult;
|
||||
|
@ -311,7 +340,7 @@ impl UserOrganization {
|
|||
"UseTotp": true,
|
||||
// "UseScim": false, // Not supported (Not AGPLv3 Licensed)
|
||||
"UsePolicies": true,
|
||||
"UseApi": false, // Not supported
|
||||
"UseApi": true,
|
||||
"SelfHost": true,
|
||||
"HasPublicAndPrivateKeys": org.private_key.is_some() && org.public_key.is_some(),
|
||||
"ResetPasswordEnrolled": self.reset_password_key.is_some(),
|
||||
|
@ -750,6 +779,50 @@ impl UserOrganization {
|
|||
}
|
||||
}
|
||||
|
||||
impl OrganizationApiKey {
|
||||
pub async fn save(&self, conn: &DbConn) -> EmptyResult {
|
||||
db_run! { conn:
|
||||
sqlite, mysql {
|
||||
match diesel::replace_into(organization_api_key::table)
|
||||
.values(OrganizationApiKeyDb::to_db(self))
|
||||
.execute(conn)
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||
diesel::update(organization_api_key::table)
|
||||
.filter(organization_api_key::uuid.eq(&self.uuid))
|
||||
.set(OrganizationApiKeyDb::to_db(self))
|
||||
.execute(conn)
|
||||
.map_res("Error saving organization")
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}.map_res("Error saving organization")
|
||||
|
||||
}
|
||||
postgresql {
|
||||
let value = OrganizationApiKeyDb::to_db(self);
|
||||
diesel::insert_into(organization_api_key::table)
|
||||
.values(&value)
|
||||
.on_conflict(organization_api_key::uuid)
|
||||
.do_update()
|
||||
.set(&value)
|
||||
.execute(conn)
|
||||
.map_res("Error saving organization")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn find_by_org_uuid(org_uuid: &str, conn: &DbConn) -> Option<Self> {
|
||||
db_run! { conn: {
|
||||
organization_api_key::table
|
||||
.filter(organization_api_key::org_uuid.eq(org_uuid))
|
||||
.first::<OrganizationApiKeyDb>(conn)
|
||||
.ok().from_db()
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -229,6 +229,16 @@ table! {
|
|||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
organization_api_key (uuid, org_uuid) {
|
||||
uuid -> Text,
|
||||
org_uuid -> Text,
|
||||
atype -> Integer,
|
||||
api_key -> Text,
|
||||
revision_date -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
emergency_access (uuid) {
|
||||
uuid -> Text,
|
||||
|
@ -292,6 +302,7 @@ joinable!(users_collections -> collections (collection_uuid));
|
|||
joinable!(users_collections -> users (user_uuid));
|
||||
joinable!(users_organizations -> organizations (org_uuid));
|
||||
joinable!(users_organizations -> users (user_uuid));
|
||||
joinable!(organization_api_key -> organizations (org_uuid));
|
||||
joinable!(emergency_access -> users (grantor_uuid));
|
||||
joinable!(groups -> organizations (organizations_uuid));
|
||||
joinable!(groups_users -> users_organizations (users_organizations_uuid));
|
||||
|
@ -316,6 +327,7 @@ allow_tables_to_appear_in_same_query!(
|
|||
users,
|
||||
users_collections,
|
||||
users_organizations,
|
||||
organization_api_key,
|
||||
emergency_access,
|
||||
groups,
|
||||
groups_users,
|
||||
|
|
|
@ -229,6 +229,16 @@ table! {
|
|||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
organization_api_key (uuid, org_uuid) {
|
||||
uuid -> Text,
|
||||
org_uuid -> Text,
|
||||
atype -> Integer,
|
||||
api_key -> Text,
|
||||
revision_date -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
emergency_access (uuid) {
|
||||
uuid -> Text,
|
||||
|
@ -292,6 +302,7 @@ joinable!(users_collections -> collections (collection_uuid));
|
|||
joinable!(users_collections -> users (user_uuid));
|
||||
joinable!(users_organizations -> organizations (org_uuid));
|
||||
joinable!(users_organizations -> users (user_uuid));
|
||||
joinable!(organization_api_key -> organizations (org_uuid));
|
||||
joinable!(emergency_access -> users (grantor_uuid));
|
||||
joinable!(groups -> organizations (organizations_uuid));
|
||||
joinable!(groups_users -> users_organizations (users_organizations_uuid));
|
||||
|
@ -316,6 +327,7 @@ allow_tables_to_appear_in_same_query!(
|
|||
users,
|
||||
users_collections,
|
||||
users_organizations,
|
||||
organization_api_key,
|
||||
emergency_access,
|
||||
groups,
|
||||
groups_users,
|
||||
|
|
|
@ -229,6 +229,16 @@ table! {
|
|||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
organization_api_key (uuid, org_uuid) {
|
||||
uuid -> Text,
|
||||
org_uuid -> Text,
|
||||
atype -> Integer,
|
||||
api_key -> Text,
|
||||
revision_date -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
emergency_access (uuid) {
|
||||
uuid -> Text,
|
||||
|
@ -293,6 +303,7 @@ joinable!(users_collections -> users (user_uuid));
|
|||
joinable!(users_organizations -> organizations (org_uuid));
|
||||
joinable!(users_organizations -> users (user_uuid));
|
||||
joinable!(users_organizations -> ciphers (org_uuid));
|
||||
joinable!(organization_api_key -> organizations (org_uuid));
|
||||
joinable!(emergency_access -> users (grantor_uuid));
|
||||
joinable!(groups -> organizations (organizations_uuid));
|
||||
joinable!(groups_users -> users_organizations (users_organizations_uuid));
|
||||
|
@ -317,6 +328,7 @@ allow_tables_to_appear_in_same_query!(
|
|||
users,
|
||||
users_collections,
|
||||
users_organizations,
|
||||
organization_api_key,
|
||||
emergency_access,
|
||||
groups,
|
||||
groups_users,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue