diff --git a/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPerformanceTests.cs b/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPerformanceTests.cs index 5c35ecbdb2..4c701344a4 100644 --- a/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPerformanceTests.cs +++ b/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPerformanceTests.cs @@ -1,7 +1,9 @@ using System.Net; using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; +using Bit.Infrastructure.EntityFramework.Models; using Bit.Seeder.Recipes; +using Microsoft.AspNetCore.Identity; using Xunit; using Xunit.Abstractions; @@ -18,7 +20,8 @@ public class OrganizationUsersControllerPerformanceTest(ITestOutputHelper testOu var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var seeder = new OrganizationWithUsersRecipe(db); + var passwordHasher = factory.Services.CreateScope().ServiceProvider.GetService>(); + var seeder = new OrganizationWithUsersRecipe(db, passwordHasher); var orgId = seeder.Seed("Org", seats, "large.test"); diff --git a/util/RustSdk/RustSdkService.cs b/util/RustSdk/RustSdkService.cs index 75ef72ab56..ee01d56fee 100644 --- a/util/RustSdk/RustSdkService.cs +++ b/util/RustSdk/RustSdkService.cs @@ -7,11 +7,26 @@ namespace Bit.RustSDK; public class UserKeys { public required string MasterPasswordHash { get; set; } + /// + /// Base64 encoded UserKey + /// + public required string Key { get; set; } public required string EncryptedUserKey { get; set; } public required string PublicKey { get; set; } public required string PrivateKey { get; set; } } +public class OrganizationKeys +{ + /// + /// Base64 encoded SymmetricCryptoKey + /// + public required string Key { get; set; } + + public required string PublicKey { get; set; } + public required string PrivateKey { get; set; } +} + /// /// Service implementation that provides a C# friendly interface to the Rust SDK /// @@ -38,43 +53,32 @@ public class RustSdkService } } - /// - /// Hashes a password using the native implementation - /// - /// User email - /// User password - /// The hashed password as a string - /// Thrown when email or password is null - /// Thrown when email or password is empty - /// Thrown when the native operation fails - public unsafe string HashPassword(string email, string password) + public unsafe OrganizationKeys GenerateOrganizationKeys() { - // Convert strings to null-terminated byte arrays - var emailBytes = StringToRustString(email); - var passwordBytes = StringToRustString(password); + var resultPtr = NativeMethods.generate_organization_keys(); - try - { - fixed (byte* emailPtr = emailBytes) - fixed (byte* passwordPtr = passwordBytes) - { - var resultPtr = NativeMethods.hash_password(emailPtr, passwordPtr); + var result = TakeAndDestroyRustString(resultPtr); - var result = TakeAndDestroyRustString(resultPtr); + return JsonSerializer.Deserialize(result, CaseInsensitiveOptions)!; + } - return result; - } - } - catch (RustSdkException) + public unsafe string GenerateUserOrganizationKey(string userKey, string orgKey) + { + var userKeyBytes = StringToRustString(userKey); + var orgKeyBytes = StringToRustString(orgKey); + + fixed (byte* userKeyPtr = userKeyBytes) + fixed (byte* orgKeyPtr = orgKeyBytes) { - throw; // Re-throw our custom exceptions - } - catch (Exception ex) - { - throw new RustSdkException($"Failed to hash password: {ex.Message}", ex); + var resultPtr = NativeMethods.generate_user_organization_key(userKeyPtr, orgKeyPtr); + + var result = TakeAndDestroyRustString(resultPtr); + + return result; } } + private static byte[] StringToRustString(string str) { return Encoding.UTF8.GetBytes(str + '\0'); diff --git a/util/RustSdk/RustSdkServiceFactory.cs b/util/RustSdk/RustSdkServiceFactory.cs index 5a1e44eb22..e19275aacb 100644 --- a/util/RustSdk/RustSdkServiceFactory.cs +++ b/util/RustSdk/RustSdkServiceFactory.cs @@ -5,15 +5,6 @@ /// public static class RustSdkServiceFactory { - /// - /// Creates a new instance of the Rust SDK service - /// - /// A new IRustSdkService instance - public static RustSdkService Create() - { - return new RustSdkService(); - } - /// /// Creates a singleton instance of the Rust SDK service (thread-safe) /// @@ -25,6 +16,6 @@ public static class RustSdkServiceFactory private static class SingletonHolder { - internal static readonly RustSdkService Instance = new RustSdkService(); + internal static readonly RustSdkService Instance = new(); } } diff --git a/util/RustSdk/rust/Cargo.lock b/util/RustSdk/rust/Cargo.lock index 85a819427b..1665f387c4 100644 --- a/util/RustSdk/rust/Cargo.lock +++ b/util/RustSdk/rust/Cargo.lock @@ -135,7 +135,7 @@ checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bitwarden-api-api" version = "1.0.0" -source = "git+https://github.com/bitwarden/sdk-internal.git?rev=b0c950dad701bc419c76e8a7d37bf5c17a6909d6#b0c950dad701bc419c76e8a7d37bf5c17a6909d6" +source = "git+https://github.com/bitwarden/sdk-internal.git?rev=29c6158636d50141788e41736d15f2f6c7bc7fa8#29c6158636d50141788e41736d15f2f6c7bc7fa8" dependencies = [ "reqwest", "serde", @@ -149,7 +149,7 @@ dependencies = [ [[package]] name = "bitwarden-api-identity" version = "1.0.0" -source = "git+https://github.com/bitwarden/sdk-internal.git?rev=b0c950dad701bc419c76e8a7d37bf5c17a6909d6#b0c950dad701bc419c76e8a7d37bf5c17a6909d6" +source = "git+https://github.com/bitwarden/sdk-internal.git?rev=29c6158636d50141788e41736d15f2f6c7bc7fa8#29c6158636d50141788e41736d15f2f6c7bc7fa8" dependencies = [ "reqwest", "serde", @@ -163,8 +163,9 @@ dependencies = [ [[package]] name = "bitwarden-core" version = "1.0.0" -source = "git+https://github.com/bitwarden/sdk-internal.git?rev=b0c950dad701bc419c76e8a7d37bf5c17a6909d6#b0c950dad701bc419c76e8a7d37bf5c17a6909d6" +source = "git+https://github.com/bitwarden/sdk-internal.git?rev=29c6158636d50141788e41736d15f2f6c7bc7fa8#29c6158636d50141788e41736d15f2f6c7bc7fa8" dependencies = [ + "async-trait", "base64", "bitwarden-api-api", "bitwarden-api-identity", @@ -181,10 +182,11 @@ dependencies = [ "rustls-platform-verifier", "schemars 0.8.22", "serde", + "serde_bytes", "serde_json", "serde_qs", "serde_repr", - "thiserror 2.0.12", + "thiserror 1.0.69", "uuid", "zeroize", ] @@ -192,7 +194,7 @@ dependencies = [ [[package]] name = "bitwarden-crypto" version = "1.0.0" -source = "git+https://github.com/bitwarden/sdk-internal.git?rev=b0c950dad701bc419c76e8a7d37bf5c17a6909d6#b0c950dad701bc419c76e8a7d37bf5c17a6909d6" +source = "git+https://github.com/bitwarden/sdk-internal.git?rev=29c6158636d50141788e41736d15f2f6c7bc7fa8#29c6158636d50141788e41736d15f2f6c7bc7fa8" dependencies = [ "aes", "argon2", @@ -220,7 +222,7 @@ dependencies = [ "sha1", "sha2", "subtle", - "thiserror 2.0.12", + "thiserror 1.0.69", "typenum", "uuid", "zeroize", @@ -230,7 +232,7 @@ dependencies = [ [[package]] name = "bitwarden-error" version = "1.0.0" -source = "git+https://github.com/bitwarden/sdk-internal.git?rev=b0c950dad701bc419c76e8a7d37bf5c17a6909d6#b0c950dad701bc419c76e8a7d37bf5c17a6909d6" +source = "git+https://github.com/bitwarden/sdk-internal.git?rev=29c6158636d50141788e41736d15f2f6c7bc7fa8#29c6158636d50141788e41736d15f2f6c7bc7fa8" dependencies = [ "bitwarden-error-macro", ] @@ -238,7 +240,7 @@ dependencies = [ [[package]] name = "bitwarden-error-macro" version = "1.0.0" -source = "git+https://github.com/bitwarden/sdk-internal.git?rev=b0c950dad701bc419c76e8a7d37bf5c17a6909d6#b0c950dad701bc419c76e8a7d37bf5c17a6909d6" +source = "git+https://github.com/bitwarden/sdk-internal.git?rev=29c6158636d50141788e41736d15f2f6c7bc7fa8#29c6158636d50141788e41736d15f2f6c7bc7fa8" dependencies = [ "darling", "proc-macro2", @@ -249,16 +251,16 @@ dependencies = [ [[package]] name = "bitwarden-state" version = "1.0.0" -source = "git+https://github.com/bitwarden/sdk-internal.git?rev=b0c950dad701bc419c76e8a7d37bf5c17a6909d6#b0c950dad701bc419c76e8a7d37bf5c17a6909d6" +source = "git+https://github.com/bitwarden/sdk-internal.git?rev=29c6158636d50141788e41736d15f2f6c7bc7fa8#29c6158636d50141788e41736d15f2f6c7bc7fa8" dependencies = [ "async-trait", - "thiserror 2.0.12", + "thiserror 1.0.69", ] [[package]] name = "bitwarden-uuid" version = "1.0.0" -source = "git+https://github.com/bitwarden/sdk-internal.git?rev=b0c950dad701bc419c76e8a7d37bf5c17a6909d6#b0c950dad701bc419c76e8a7d37bf5c17a6909d6" +source = "git+https://github.com/bitwarden/sdk-internal.git?rev=29c6158636d50141788e41736d15f2f6c7bc7fa8#29c6158636d50141788e41736d15f2f6c7bc7fa8" dependencies = [ "bitwarden-uuid-macro", ] @@ -266,7 +268,7 @@ dependencies = [ [[package]] name = "bitwarden-uuid-macro" version = "1.0.0" -source = "git+https://github.com/bitwarden/sdk-internal.git?rev=b0c950dad701bc419c76e8a7d37bf5c17a6909d6#b0c950dad701bc419c76e8a7d37bf5c17a6909d6" +source = "git+https://github.com/bitwarden/sdk-internal.git?rev=29c6158636d50141788e41736d15f2f6c7bc7fa8#29c6158636d50141788e41736d15f2f6c7bc7fa8" dependencies = [ "quote", "syn", @@ -1894,6 +1896,7 @@ dependencies = [ name = "sdk" version = "0.1.0" dependencies = [ + "base64", "bitwarden-core", "bitwarden-crypto", "csbindgen", diff --git a/util/RustSdk/rust/Cargo.toml b/util/RustSdk/rust/Cargo.toml index 82e1c5777c..8a9c4378cb 100644 --- a/util/RustSdk/rust/Cargo.toml +++ b/util/RustSdk/rust/Cargo.toml @@ -12,8 +12,9 @@ repository = "https://github.com/bitwarden/server" crate-type = ["cdylib"] [dependencies] -bitwarden-core = { git = "https://github.com/bitwarden/sdk-internal.git", rev = "b0c950dad701bc419c76e8a7d37bf5c17a6909d6" } -bitwarden-crypto = { git = "https://github.com/bitwarden/sdk-internal.git", rev = "b0c950dad701bc419c76e8a7d37bf5c17a6909d6" } +base64 = "0.22.1" +bitwarden-core = { git = "https://github.com/bitwarden/sdk-internal.git", rev = "29c6158636d50141788e41736d15f2f6c7bc7fa8" } +bitwarden-crypto = { git = "https://github.com/bitwarden/sdk-internal.git", rev = "29c6158636d50141788e41736d15f2f6c7bc7fa8" } serde = "=1.0.219" serde_json = "=1.0.141" diff --git a/util/RustSdk/rust/src/lib.rs b/util/RustSdk/rust/src/lib.rs index 27dc3b2c4c..58fbbde741 100644 --- a/util/RustSdk/rust/src/lib.rs +++ b/util/RustSdk/rust/src/lib.rs @@ -4,7 +4,12 @@ use std::{ num::NonZeroU32, }; -use bitwarden_crypto::{HashPurpose, Kdf, MasterKey}; +use base64::{engine::general_purpose::STANDARD, Engine}; + +use bitwarden_crypto::{ + AsymmetricPublicCryptoKey, BitwardenLegacyKeyBytes, HashPurpose, Kdf, MasterKey, + SpkiPublicKeyBytes, SymmetricCryptoKey, UnsignedSharedKey, UserKey, +}; #[no_mangle] pub extern "C" fn my_add(x: i32, y: i32) -> i32 { @@ -29,13 +34,14 @@ pub unsafe extern "C" fn generate_user_keys( .derive_master_key_hash(password.as_bytes(), HashPurpose::ServerAuthorization) .unwrap(); let (user_key, encrypted_user_key) = master_key.make_user_key().unwrap(); - let keys = user_key.make_key_pair().unwrap(); + let keypair = user_key.make_key_pair().unwrap(); let json = serde_json::json!({ "masterPasswordHash": master_password_hash, + "key": user_key.0.to_base64(), "encryptedUserKey": encrypted_user_key.to_string(), - "publicKey": keys.public.to_string(), - "privateKey": keys.private.to_string(), + "publicKey": keypair.public.to_string(), + "privateKey": keypair.private.to_string(), }) .to_string(); @@ -44,31 +50,51 @@ pub unsafe extern "C" fn generate_user_keys( result.into_raw() } -/// # Safety -/// -/// The `email` and `password` pointers must be valid null-terminated C strings. -/// Both pointers must be non-null and point to valid memory for the duration of the function call. #[no_mangle] -pub unsafe extern "C" fn hash_password( - email: *const c_char, - password: *const c_char, +pub unsafe extern "C" fn generate_organization_keys() -> *const c_char { + let key = SymmetricCryptoKey::make_aes256_cbc_hmac_key(); + + let key = UserKey::new(key); + let keypair = key.make_key_pair().expect("Failed to generate key pair"); + + let json = serde_json::json!({ + "key": key.0.to_base64(), + "publicKey": keypair.public.to_string(), + "privateKey": keypair.private.to_string(), + }) + .to_string(); + + let result = CString::new(json).unwrap(); + + result.into_raw() +} + +#[no_mangle] +pub unsafe extern "C" fn generate_user_organization_key( + user_public_key: *const c_char, + organization_key: *const c_char, ) -> *const c_char { - let kdf = Kdf::PBKDF2 { - iterations: NonZeroU32::new(600_000).unwrap(), - }; + let user_public_key = CStr::from_ptr(user_public_key).to_str().unwrap().to_owned(); + let organization_key = CStr::from_ptr(organization_key) + .to_str() + .unwrap() + .to_owned(); - let email = CStr::from_ptr(email).to_str().unwrap(); - let password = CStr::from_ptr(password).to_str().unwrap(); + let user_public_key = STANDARD.decode(user_public_key).unwrap(); + let organization_key = STANDARD.decode(organization_key).unwrap(); - let master_key = MasterKey::derive(password, email, &kdf).unwrap(); + let encapsulation_key = + AsymmetricPublicCryptoKey::from_der(&SpkiPublicKeyBytes::from(user_public_key)).unwrap(); - let res = master_key - .derive_master_key_hash(password.as_bytes(), HashPurpose::ServerAuthorization) - .unwrap(); + let encrypted_key = UnsignedSharedKey::encapsulate_key_unsigned( + &SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(organization_key)).unwrap(), + &encapsulation_key, + ) + .unwrap(); - let res = CString::new(res).unwrap(); + let result = CString::new(encrypted_key.to_string()).unwrap(); - res.into_raw() + result.into_raw() } /// # Safety diff --git a/util/Seeder/Factories/OrganizationSeeder.cs b/util/Seeder/Factories/OrganizationSeeder.cs index 5e5cb17419..6363829de5 100644 --- a/util/Seeder/Factories/OrganizationSeeder.cs +++ b/util/Seeder/Factories/OrganizationSeeder.cs @@ -2,14 +2,19 @@ using Bit.Core.Enums; using Bit.Infrastructure.EntityFramework.AdminConsole.Models; using Bit.Infrastructure.EntityFramework.Models; +using Bit.RustSDK; namespace Bit.Seeder.Factories; public class OrganizationSeeder { - public static Organization CreateEnterprise(string name, string domain, int seats) + public static (Organization organization, string key) CreateEnterprise(string name, string domain, int seats) { - return new Organization + var nativeService = RustSdkServiceFactory.CreateSingleton(); + + var keys = nativeService.GenerateOrganizationKeys(); + + var organization = new Organization { Id = Guid.NewGuid(), Name = name, @@ -20,23 +25,28 @@ public class OrganizationSeeder // Currently hardcoded to the values from https://github.com/bitwarden/sdk-internal/blob/main/crates/bitwarden-core/src/client/test_accounts.rs. // TODO: These should be dynamically generated by the SDK. - PublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmIJbGMk6eZqVE7UxhZ46Weu2jKciqOiOkSVYtGvs61rfe9AXxtLaaZEKN4d4DmkZcF6dna2eXNxZmb7U4pwlttye8ksqISe6IUAZQox7auBpjopdCEPhKRg3BD/u8ks9UxSxgWe+fpebjt6gd5hsl1/5HOObn7SeU6EEU04cp3/eH7a4OTdXxB8oN62HGV9kM/ubM1goILgjoSJDbihMK0eb7b8hPHwcA/YOgKKiu/N3FighccdSMD5Pk+HfjacsFNZQa2EsqW09IvvSZ+iL6HQeZ1vwc/6TO1J7EOfJZFQcjoEL9LVI693efYoMZSmrPEWziZ4PvwpOOGo6OObyMQIDAQAB", - PrivateKey = "2.6FggyKVyaKQsfohi5yqgbg==|UU2JeafOB41L5UscGmf4kq15JGDf3Bkf67KECiehTODzbWctVLTgyDk0Qco8/6CMN6nZGXjxR2A4r5ExhmwRNsNxd77G+MprkmiJz+7w33ROZ1ouQO5XjD3wbQ3ssqNiTKId6yAUPBvuAZRixVApauTuADc8QWGixqCQcqZzmU7YSBBIPf652/AEYr4Tk64YihoE39pHiK8MRbTLdRt3EF4LSMugPAPM24vCgUv3w1TD3Fj6sDg/6oi3flOV9SJZX4vCiUXbDNEuD/p2aQrEXVbaxweFOHjTe7F4iawjXw3nG3SO8rUBHcxbhDDVx5rjYactbW5QvHWiyla6uLb6o8WHBneg2EjTEwAHOZE/rBjcqmAJb2sVp1E0Kwq8ycGmL69vmqJPC1GqVTohAQvmEkaxIPpfq24Yb9ZPrADA7iEXBKuAQ1FphFUVgJBJGJbd60sOV1Rz1T+gUwS4wCNQ4l3LG1S22+wzUVlEku5DXFnT932tatqTyWEthqPqLCt6dL1+qa94XLpeHagXAx2VGe8n8IlcADtxqS+l8xQ4heT12WO9kC316vqvg1mnsI56faup9hb3eT9ZpKyxSBGYOphlTWfV1Y/v64f5PYvTo4aL0IYHyLY/9Qi72vFmOpPeHBYgD5t3j+H2CsiU1PkYsBggOmD7xW8FDuT6HWVvwhEJqeibVPK0Lhyj6tgvlSIAvFUaSMFPlmwFNmwfj/AHUhr9KuTfsBFTZ10yy9TZVgf+EofwnrxHBaWUgdD40aHoY1VjfG33iEuajb6buxG3pYFyPNhJNzeLZisUKIDRMQpUHrsE22EyrFFran3tZGdtcyIEK4Q1F0ULYzJ6T9iY25/ZgPy3pEAAMZCtqo3s+GjX295fWIHfMcnjMgNUHPjExjWBHa+ggK9iQXkFpBVyYB1ga/+0eiIhiek3PlgtvpDrqF7TsLK+ROiBw2GJ7uaO3EEXOj2GpNBuEJ5CdodhZkwzhwMcSatgDHkUuNVu0iVbF6/MxVdOxWXKO+jCYM6PZk/vAhLYqpPzu2T2Uyz4nkDs2Tiq61ez6FoCrzdHIiyIxVTzUQH8G9FgSmtaZ7GCbqlhnurYgcMciwPzxg0hpAQT+NZw1tVEii9vFSpJJbGJqNhORKfKh/Mu1P/9LOQq7Y0P2FIR3x/eUVEQ7CGv2jVtO5ryGSmKeq/P9Fr54wTPaNiqN2K+leACUznCdUWw8kZo/AsBcrOe4OkRX6k8LC3oeJXy06DEToatxEvPYemUauhxiXRw8nfNMqc4LyJq2bbT0zCgJHoqpozPdNg6AYWcoIobgAGu7ZQGq+oE1MT3GZxotMPe/NUJiAc5YE9Thb5Yf3gyno71pyqPTVl/6IQuh4SUz7rkgwF/aVHEnr4aUYNoc0PEzd2Me0jElsA3GAneq1I/wngutOWgTViTK4Nptr5uIzMVQs9H1rOMJNorP8b02t1NDu010rSsib9GaaJJq4r4iy46laQOxWoU0ex26arYnk+jw4833WSCTVBIprTgizZ+fKjoY0xwXvI2oOvGNEUCtGFvKFORTaQrlaXZIg1toa2BBVNicyONbwnI3KIu3MgGJ2SlCVXJn8oHFppVHFCdwgN1uDzGiKAhjvr0sZTUtXin2f2CszPTbbo=|fUhbVKrr8CSKE7TZJneXpDGraj5YhRrq9ESo206S+BY=", + PublicKey = keys.PublicKey, + PrivateKey = keys.PrivateKey, }; + + return (organization, keys.Key); } } -public static class OrgnaizationExtensions +public static class OrganizationExtensions { - public static OrganizationUser CreateOrganizationUser(this Organization organization, User user) + public static OrganizationUser CreateOrganizationUser(this Organization organization, User user, string orgKey) { + var nativeService = RustSdkServiceFactory.CreateSingleton(); + + var userOrgKey = nativeService.GenerateUserOrganizationKey(user.PublicKey!, orgKey); + return new OrganizationUser { Id = Guid.NewGuid(), OrganizationId = organization.Id, UserId = user.Id, - - Key = "4.rY01mZFXHOsBAg5Fq4gyXuklWfm6mQASm42DJpx05a+e2mmp+P5W6r54WU2hlREX0uoTxyP91bKKwickSPdCQQ58J45LXHdr9t2uzOYyjVzpzebFcdMw1eElR9W2DW8wEk9+mvtWvKwu7yTebzND+46y1nRMoFydi5zPVLSlJEf81qZZ4Uh1UUMLwXz+NRWfixnGXgq2wRq1bH0n3mqDhayiG4LJKgGdDjWXC8W8MMXDYx24SIJrJu9KiNEMprJE+XVF9nQVNijNAjlWBqkDpsfaWTUfeVLRLctfAqW1blsmIv4RQ91PupYJZDNc8nO9ZTF3TEVM+2KHoxzDJrLs2Q==", + Key = userOrgKey, Type = OrganizationUserType.Admin, Status = OrganizationUserStatusType.Confirmed }; diff --git a/util/Seeder/Factories/UserSeeder.cs b/util/Seeder/Factories/UserSeeder.cs index 80d6c13159..ec65bff085 100644 --- a/util/Seeder/Factories/UserSeeder.cs +++ b/util/Seeder/Factories/UserSeeder.cs @@ -9,7 +9,7 @@ namespace Bit.Seeder.Factories; public class UserSeeder { - public static User CreateUser(IPasswordHasher passwordHasher, string email) + public static (User user, string userKey) CreateUser(IPasswordHasher passwordHasher, string email) { var nativeService = RustSdkServiceFactory.CreateSingleton(); var keys = nativeService.GenerateUserKeys(email, "asdfasdfasdf"); @@ -31,6 +31,6 @@ public class UserSeeder user.MasterPassword = passwordHasher.HashPassword(user, keys.MasterPasswordHash); - return user; + return (user, keys.Key); } } diff --git a/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs b/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs index 776a32e5bb..e55d72ab83 100644 --- a/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs +++ b/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs @@ -11,28 +11,28 @@ public class OrganizationWithUsersRecipe(DatabaseContext db, IPasswordHasher(); var additionalOrgUsers = new List(); for (var i = 0; i < users; i++) { - var additionalUser = UserSeeder.CreateUser(passwordHasher, $"user{i}@{domain}"); + var (additionalUser, _) = UserSeeder.CreateUser(passwordHasher, $"user{i}@{domain}"); additionalUsers.Add(additionalUser); - additionalOrgUsers.Add(organization.CreateOrganizationUser(additionalUser)); + additionalOrgUsers.Add(organization.CreateOrganizationUser(additionalUser, orgKey)); } - //db.Add(organization); + db.Add(organization); db.Add(user); - //db.Add(orgUser); + db.Add(orgUser); db.SaveChanges(); // Use LinqToDB's BulkCopy for significant better performance - //db.BulkCopy(additionalUsers); - //db.BulkCopy(additionalOrgUsers); + db.BulkCopy(additionalUsers); + db.BulkCopy(additionalOrgUsers); return organization.Id; }