mirror of
https://github.com/bitwarden/server
synced 2025-12-10 05:13:48 +00:00
* [PM-21034] Database changes for signature keypairs (#5906) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Drop view if exists * Enable nullable * Replace with create or alter view * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * [PM-21034] Implement api changes to retreive signing keys (#5932) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * [PM-22384] Implement key-rotation based enrollment to user-crypto v2 (#5934) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Cleanup * Add migration to user encryption v2 * Fix build * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Cleanup * Cleanup * Fix build * Fix test * Add validation * Fix test * Apply fixes * Fix tests * Improve tests * Add tests * Add error message validation * Fix tests * Fix tests * Fix test * Add test * Fix tests and errors * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Fix build * Fix namespace * Make signedpublickey optional * Remove unused file * Fix cases for request data conversion * Revert constructor change * Undo comments change * Apply fixes * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests * Fix build of integration tests * Attempt to fix tests * Add test * Move v2 encryption user async below public functions * Add todo * Rename to have async suffix * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Address feedback * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test coverage * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Split up validation from rotation * Fix tests * Increase test coverage * Rename tests * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test for no signature keypair data * Fix build * Enable nullable * Fix build * Clean up data model * Fix tests * Cleanup --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Fix build * [PM-22862] Account security version (#5995) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Cleanup * Add migration to user encryption v2 * Fix build * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Cleanup * Cleanup * Fix build * Fix test * Add validation * Fix test * Apply fixes * Fix tests * Improve tests * Add tests * Add error message validation * Fix tests * Fix tests * Fix test * Add test * Fix tests and errors * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Fix build * Fix namespace * Make signedpublickey optional * Remove unused file * Fix cases for request data conversion * Revert constructor change * Undo comments change * Apply fixes * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests * Fix build of integration tests * Attempt to fix tests * Add test * Move v2 encryption user async below public functions * Add todo * Rename to have async suffix * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Address feedback * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test coverage * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Split up validation from rotation * Fix tests * Increase test coverage * Rename tests * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test for no signature keypair data * Fix build * Enable nullable * Fix build * Clean up data model * Fix tests * Merge branch 'km/signing-upgrade-rotation' into km/account-security-version * Add security state to rotation * Update tests * Update tests and check for security state in v2 model * Cleanup * Add tests * Add security state data to integration test * Re-sort and remove limit * Update migrations * Fix sql * Fix sql * Fix sql * Fix fixture * Fix test * Fix test * Fix test --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * [PM-22853] Add feature flag (#6090) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Cleanup * Add migration to user encryption v2 * Fix build * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Cleanup * Cleanup * Fix build * Fix test * Add validation * Fix test * Apply fixes * Fix tests * Improve tests * Add tests * Add error message validation * Fix tests * Fix tests * Fix test * Add test * Fix tests and errors * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Fix build * Fix namespace * Make signedpublickey optional * Remove unused file * Fix cases for request data conversion * Revert constructor change * Undo comments change * Apply fixes * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests * Fix build of integration tests * Attempt to fix tests * Add test * Move v2 encryption user async below public functions * Add todo * Rename to have async suffix * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Address feedback * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test coverage * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Split up validation from rotation * Fix tests * Increase test coverage * Rename tests * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test for no signature keypair data * Fix build * Enable nullable * Fix build * Clean up data model * Fix tests * Merge branch 'km/signing-upgrade-rotation' into km/account-security-version * Add security state to rotation * Update tests * Add feature flag * Update tests and check for security state in v2 model * Cleanup * Add tests * Add security state data to integration test * Re-sort and remove limit * Update migrations * Fix sql * Fix sql * Fix sql * Fix fixture * Fix test * Fix test * Fix test --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * [PM-23222] Update revision date on key rotation (#6038) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Cleanup * Add migration to user encryption v2 * Fix build * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Cleanup * Cleanup * Fix build * Fix test * Add validation * Fix test * Apply fixes * Fix tests * Improve tests * Add tests * Add error message validation * Fix tests * Fix tests * Fix test * Add test * Fix tests and errors * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Fix build * Fix namespace * Make signedpublickey optional * Remove unused file * Fix cases for request data conversion * Revert constructor change * Undo comments change * Apply fixes * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests * Fix build of integration tests * Attempt to fix tests * Add test * Move v2 encryption user async below public functions * Add todo * Rename to have async suffix * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Address feedback * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test coverage * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Split up validation from rotation * Fix tests * Increase test coverage * Rename tests * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test for no signature keypair data * Fix build * Enable nullable * Fix build * Clean up data model * Fix tests * Merge branch 'km/signing-upgrade-rotation' into km/account-security-version * Add security state to rotation * Update tests * Update revision date on key rotation * Update tests and check for security state in v2 model * Cleanup * Add tests * Add security state data to integration test * Re-sort and remove limit * Update migrations * Fix sql * Fix sql * Fix sql * Fix fixture * Fix test * Fix test * Fix test * Add test for change date --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Fix signing keys * Update sql migrations * Fix tests * Add keys to identity token response * Fix tests * Fix tests * Fix formatting * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Infrastructure.Dapper/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Requests/SignatureKeyPairRequestModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Requests/PublicKeyEncryptionKeyPairRequestModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Entities/UserSignatureKeyPair.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Repositories/IUserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Queries/UserAccountKeysQuery.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/PublicKeyEncryptionKeyPairData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Entities/UserSignatureKeyPair.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/RotateUserAccountKeysData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/SignatureKeyPairData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/SecurityStateData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/UserAccountKeysData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Request/SecurityStateModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Response/PublicKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Response/PublicKeyEncryptionKeyPairResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Queries/Interfaces/IUserAcountKeysQuery.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Response/SignatureKeyPairResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove unnecessary file * Add eof spacing * Move models * Fix build * Move models to API subdirectory * Rename model * Remove migrations * Add new ef migrations * Remove empty line * Only query account keys if the user has keys * Dotnet format * Fix test * Update test/Identity.Test/IdentityServer/BaseRequestValidatorTests.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Apply suggestion * Fix whitespace * Force camel case on response models * Address feedback for sql files * Fix build * Make index unique * Add contstraints * Fix sql * Fix order * Cleanup * Fix build * Update migrations * Update EF migrations * Change parameters to nvarchar * Update to Varchar * Apply feedback * Move refresh view * Attempt to fix build * Undo sql changes * Apply feedback about varchar * Apply feedback about refresh view * Apply feedback about new lines * Address SQL feedback * Re-sort columns * Fix build * Fix order * Fix build --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>
560 lines
25 KiB
C#
560 lines
25 KiB
C#
#nullable enable
|
|
using System.Net;
|
|
using Bit.Api.IntegrationTest.Factories;
|
|
using Bit.Api.IntegrationTest.Helpers;
|
|
using Bit.Api.KeyManagement.Models.Requests;
|
|
using Bit.Api.Tools.Models.Request;
|
|
using Bit.Api.Vault.Models;
|
|
using Bit.Api.Vault.Models.Request;
|
|
using Bit.Core.Auth.Entities;
|
|
using Bit.Core.Auth.Enums;
|
|
using Bit.Core.Auth.Models.Api.Request.Accounts;
|
|
using Bit.Core.Billing.Enums;
|
|
using Bit.Core.Entities;
|
|
using Bit.Core.Enums;
|
|
using Bit.Core.KeyManagement.Entities;
|
|
using Bit.Core.KeyManagement.Enums;
|
|
using Bit.Core.KeyManagement.Models.Api.Request;
|
|
using Bit.Core.KeyManagement.Repositories;
|
|
using Bit.Core.Repositories;
|
|
using Bit.Core.Vault.Enums;
|
|
using Bit.Test.Common.AutoFixture.Attributes;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Xunit;
|
|
|
|
namespace Bit.Api.IntegrationTest.KeyManagement.Controllers;
|
|
|
|
public class AccountsKeyManagementControllerTests : IClassFixture<ApiApplicationFactory>, IAsyncLifetime
|
|
{
|
|
private static readonly string _mockEncryptedString =
|
|
"2.AOs41Hd8OQiCPXjyJKCiDA==|O6OHgt2U2hJGBSNGnimJmg==|iD33s8B69C8JhYYhSa4V1tArjvLr8eEaGqOV7BRo5Jk=";
|
|
private static readonly string _mockEncryptedType7String = "7.AOs41Hd8OQiCPXjyJKCiDA==";
|
|
|
|
private readonly HttpClient _client;
|
|
private readonly IEmergencyAccessRepository _emergencyAccessRepository;
|
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
|
private readonly ApiApplicationFactory _factory;
|
|
private readonly LoginHelper _loginHelper;
|
|
private readonly IUserRepository _userRepository;
|
|
private readonly IDeviceRepository _deviceRepository;
|
|
private readonly IPasswordHasher<User> _passwordHasher;
|
|
private readonly IOrganizationRepository _organizationRepository;
|
|
private readonly IUserSignatureKeyPairRepository _userSignatureKeyPairRepository;
|
|
private string _ownerEmail = null!;
|
|
|
|
public AccountsKeyManagementControllerTests(ApiApplicationFactory factory)
|
|
{
|
|
_factory = factory;
|
|
_factory.UpdateConfiguration("globalSettings:launchDarkly:flagValues:pm-12241-private-key-regeneration",
|
|
"true");
|
|
_client = factory.CreateClient();
|
|
_loginHelper = new LoginHelper(_factory, _client);
|
|
_userRepository = _factory.GetService<IUserRepository>();
|
|
_deviceRepository = _factory.GetService<IDeviceRepository>();
|
|
_emergencyAccessRepository = _factory.GetService<IEmergencyAccessRepository>();
|
|
_organizationUserRepository = _factory.GetService<IOrganizationUserRepository>();
|
|
_passwordHasher = _factory.GetService<IPasswordHasher<User>>();
|
|
_organizationRepository = _factory.GetService<IOrganizationRepository>();
|
|
_userSignatureKeyPairRepository = _factory.GetService<IUserSignatureKeyPairRepository>();
|
|
}
|
|
|
|
public async Task InitializeAsync()
|
|
{
|
|
_ownerEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com";
|
|
await _factory.LoginWithNewAccount(_ownerEmail);
|
|
}
|
|
|
|
public Task DisposeAsync()
|
|
{
|
|
_client.Dispose();
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task RegenerateKeysAsync_FeatureFlagTurnedOff_NotFound(KeyRegenerationRequestModel request)
|
|
{
|
|
// Localize factory to inject a false value for the feature flag.
|
|
var localFactory = new ApiApplicationFactory();
|
|
localFactory.UpdateConfiguration("globalSettings:launchDarkly:flagValues:pm-12241-private-key-regeneration",
|
|
"false");
|
|
var localClient = localFactory.CreateClient();
|
|
var localEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com";
|
|
var localLoginHelper = new LoginHelper(localFactory, localClient);
|
|
await localFactory.LoginWithNewAccount(localEmail);
|
|
await localLoginHelper.LoginAsync(localEmail);
|
|
|
|
request.UserKeyEncryptedUserPrivateKey = _mockEncryptedString;
|
|
|
|
var response = await localClient.PostAsJsonAsync("/accounts/key-management/regenerate-keys", request);
|
|
|
|
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task RegenerateKeysAsync_NotLoggedIn_Unauthorized(KeyRegenerationRequestModel request)
|
|
{
|
|
request.UserKeyEncryptedUserPrivateKey = _mockEncryptedString;
|
|
|
|
var response = await _client.PostAsJsonAsync("/accounts/key-management/regenerate-keys", request);
|
|
|
|
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData(OrganizationUserStatusType.Confirmed, EmergencyAccessStatusType.Confirmed)]
|
|
[BitAutoData(OrganizationUserStatusType.Confirmed, EmergencyAccessStatusType.RecoveryApproved)]
|
|
[BitAutoData(OrganizationUserStatusType.Confirmed, EmergencyAccessStatusType.RecoveryInitiated)]
|
|
[BitAutoData(OrganizationUserStatusType.Revoked, EmergencyAccessStatusType.Confirmed)]
|
|
[BitAutoData(OrganizationUserStatusType.Revoked, EmergencyAccessStatusType.RecoveryApproved)]
|
|
[BitAutoData(OrganizationUserStatusType.Revoked, EmergencyAccessStatusType.RecoveryInitiated)]
|
|
[BitAutoData(OrganizationUserStatusType.Confirmed, null)]
|
|
[BitAutoData(OrganizationUserStatusType.Revoked, null)]
|
|
[BitAutoData(OrganizationUserStatusType.Invited, EmergencyAccessStatusType.Confirmed)]
|
|
[BitAutoData(OrganizationUserStatusType.Invited, EmergencyAccessStatusType.RecoveryApproved)]
|
|
[BitAutoData(OrganizationUserStatusType.Invited, EmergencyAccessStatusType.RecoveryInitiated)]
|
|
public async Task RegenerateKeysAsync_UserInOrgOrHasDesignatedEmergencyAccess_ThrowsBadRequest(
|
|
OrganizationUserStatusType organizationUserStatus,
|
|
EmergencyAccessStatusType? emergencyAccessStatus,
|
|
KeyRegenerationRequestModel request)
|
|
{
|
|
if (organizationUserStatus is OrganizationUserStatusType.Confirmed or OrganizationUserStatusType.Revoked)
|
|
{
|
|
await CreateOrganizationUserAsync(organizationUserStatus);
|
|
}
|
|
|
|
if (emergencyAccessStatus != null)
|
|
{
|
|
await CreateDesignatedEmergencyAccessAsync(emergencyAccessStatus.Value);
|
|
}
|
|
|
|
await _loginHelper.LoginAsync(_ownerEmail);
|
|
request.UserKeyEncryptedUserPrivateKey = _mockEncryptedString;
|
|
|
|
var response = await _client.PostAsJsonAsync("/accounts/key-management/regenerate-keys", request);
|
|
|
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task RegenerateKeysAsync_Success(KeyRegenerationRequestModel request)
|
|
{
|
|
await _loginHelper.LoginAsync(_ownerEmail);
|
|
request.UserKeyEncryptedUserPrivateKey = _mockEncryptedString;
|
|
|
|
var response = await _client.PostAsJsonAsync("/accounts/key-management/regenerate-keys", request);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var user = await _userRepository.GetByEmailAsync(_ownerEmail);
|
|
Assert.NotNull(user);
|
|
Assert.Equal(request.UserPublicKey, user.PublicKey);
|
|
Assert.Equal(request.UserKeyEncryptedUserPrivateKey, user.PrivateKey);
|
|
}
|
|
|
|
private async Task CreateOrganizationUserAsync(OrganizationUserStatusType organizationUserStatus)
|
|
{
|
|
var (_, organizationUser) = await OrganizationTestHelpers.SignUpAsync(_factory,
|
|
PlanType.EnterpriseAnnually, _ownerEmail, passwordManagerSeats: 10,
|
|
paymentMethod: PaymentMethodType.Card);
|
|
organizationUser.Status = organizationUserStatus;
|
|
await _organizationUserRepository.ReplaceAsync(organizationUser);
|
|
}
|
|
|
|
private async Task CreateDesignatedEmergencyAccessAsync(EmergencyAccessStatusType emergencyAccessStatus)
|
|
{
|
|
var tempEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com";
|
|
await _factory.LoginWithNewAccount(tempEmail);
|
|
|
|
var tempUser = await _userRepository.GetByEmailAsync(tempEmail);
|
|
var user = await _userRepository.GetByEmailAsync(_ownerEmail);
|
|
var emergencyAccess = new EmergencyAccess
|
|
{
|
|
GrantorId = tempUser!.Id,
|
|
GranteeId = user!.Id,
|
|
KeyEncrypted = _mockEncryptedString,
|
|
Status = emergencyAccessStatus,
|
|
Type = EmergencyAccessType.View,
|
|
WaitTimeDays = 10,
|
|
CreationDate = DateTime.UtcNow,
|
|
RevisionDate = DateTime.UtcNow
|
|
};
|
|
await _emergencyAccessRepository.CreateAsync(emergencyAccess);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task RotateUserAccountKeysAsync_NotLoggedIn_Unauthorized(
|
|
RotateUserAccountKeysAndDataRequestModel request)
|
|
{
|
|
var response = await _client.PostAsJsonAsync("/accounts/key-management/rotate-user-account-keys", request);
|
|
|
|
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task RotateUserAccountKeysAsync_Success(RotateUserAccountKeysAndDataRequestModel request)
|
|
{
|
|
await _loginHelper.LoginAsync(_ownerEmail);
|
|
var user = await _userRepository.GetByEmailAsync(_ownerEmail);
|
|
if (user == null)
|
|
{
|
|
throw new InvalidOperationException("User not found.");
|
|
}
|
|
|
|
var password = _passwordHasher.HashPassword(user, "newMasterPassword");
|
|
user.MasterPassword = password;
|
|
user.PublicKey = "publicKey";
|
|
user.PrivateKey = _mockEncryptedString;
|
|
await _userRepository.ReplaceAsync(user);
|
|
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfType = user.Kdf;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfIterations = user.KdfIterations;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfMemory = user.KdfMemory;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfParallelism = user.KdfParallelism;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.Email = user.Email;
|
|
request.AccountKeys.AccountPublicKey = "publicKey";
|
|
request.AccountKeys.UserKeyEncryptedAccountPrivateKey = _mockEncryptedString;
|
|
request.AccountKeys.PublicKeyEncryptionKeyPair = null;
|
|
request.AccountKeys.SignatureKeyPair = null;
|
|
|
|
request.OldMasterKeyAuthenticationHash = "newMasterPassword";
|
|
|
|
request.AccountData.Ciphers =
|
|
[
|
|
new CipherWithIdRequestModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Type = CipherType.Login,
|
|
Name = _mockEncryptedString,
|
|
Login = new CipherLoginModel
|
|
{
|
|
Username = _mockEncryptedString,
|
|
Password = _mockEncryptedString,
|
|
},
|
|
},
|
|
];
|
|
request.AccountData.Folders = [
|
|
new FolderWithIdRequestModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = _mockEncryptedString,
|
|
},
|
|
];
|
|
request.AccountData.Sends = [
|
|
new SendWithIdRequestModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = _mockEncryptedString,
|
|
Key = _mockEncryptedString,
|
|
Disabled = false,
|
|
DeletionDate = DateTime.UtcNow.AddDays(1),
|
|
},
|
|
];
|
|
request.AccountUnlockData.MasterPasswordUnlockData.MasterKeyEncryptedUserKey = _mockEncryptedString;
|
|
request.AccountUnlockData.PasskeyUnlockData = [];
|
|
request.AccountUnlockData.DeviceKeyUnlockData = [];
|
|
request.AccountUnlockData.EmergencyAccessUnlockData = [];
|
|
request.AccountUnlockData.OrganizationAccountRecoveryUnlockData = [];
|
|
|
|
var response = await _client.PostAsJsonAsync("/accounts/key-management/rotate-user-account-keys", request);
|
|
var responseMessage = await response.Content.ReadAsStringAsync();
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var userNewState = await _userRepository.GetByEmailAsync(_ownerEmail);
|
|
Assert.NotNull(userNewState);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.Email, userNewState.Email);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfType, userNewState.Kdf);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfIterations, userNewState.KdfIterations);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfMemory, userNewState.KdfMemory);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfParallelism, userNewState.KdfParallelism);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PostSetKeyConnectorKeyAsync_NotLoggedIn_Unauthorized(SetKeyConnectorKeyRequestModel request)
|
|
{
|
|
var response = await _client.PostAsJsonAsync("/accounts/set-key-connector-key", request);
|
|
|
|
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PostSetKeyConnectorKeyAsync_Success(string organizationSsoIdentifier,
|
|
SetKeyConnectorKeyRequestModel request)
|
|
{
|
|
var (organization, _) = await OrganizationTestHelpers.SignUpAsync(_factory,
|
|
PlanType.EnterpriseAnnually, _ownerEmail, passwordManagerSeats: 10,
|
|
paymentMethod: PaymentMethodType.Card);
|
|
organization.UseKeyConnector = true;
|
|
organization.UseSso = true;
|
|
organization.Identifier = organizationSsoIdentifier;
|
|
await _organizationRepository.ReplaceAsync(organization);
|
|
|
|
var ssoUserEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com";
|
|
await _factory.LoginWithNewAccount(ssoUserEmail);
|
|
await _loginHelper.LoginAsync(ssoUserEmail);
|
|
|
|
await OrganizationTestHelpers.CreateUserAsync(_factory, organization.Id, ssoUserEmail,
|
|
OrganizationUserType.User, userStatusType: OrganizationUserStatusType.Invited);
|
|
|
|
var ssoUser = await _userRepository.GetByEmailAsync(ssoUserEmail);
|
|
Assert.NotNull(ssoUser);
|
|
|
|
request.Keys = new KeysRequestModel
|
|
{
|
|
PublicKey = ssoUser.PublicKey,
|
|
EncryptedPrivateKey = ssoUser.PrivateKey
|
|
};
|
|
request.Key = _mockEncryptedString;
|
|
request.OrgIdentifier = organizationSsoIdentifier;
|
|
|
|
var response = await _client.PostAsJsonAsync("/accounts/set-key-connector-key", request);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var user = await _userRepository.GetByEmailAsync(ssoUserEmail);
|
|
Assert.NotNull(user);
|
|
Assert.Equal(request.Key, user.Key);
|
|
Assert.True(user.UsesKeyConnector);
|
|
Assert.Equal(DateTime.UtcNow, user.RevisionDate, TimeSpan.FromMinutes(1));
|
|
Assert.Equal(DateTime.UtcNow, user.AccountRevisionDate, TimeSpan.FromMinutes(1));
|
|
var ssoOrganizationUser =
|
|
await _organizationUserRepository.GetByOrganizationAsync(organization.Id, user.Id);
|
|
Assert.NotNull(ssoOrganizationUser);
|
|
Assert.Equal(OrganizationUserStatusType.Accepted, ssoOrganizationUser.Status);
|
|
Assert.Equal(user.Id, ssoOrganizationUser.UserId);
|
|
Assert.Null(ssoOrganizationUser.Email);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostConvertToKeyConnectorAsync_NotLoggedIn_Unauthorized()
|
|
{
|
|
var response = await _client.PostAsJsonAsync("/accounts/convert-to-key-connector", new { });
|
|
|
|
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostConvertToKeyConnectorAsync_Success()
|
|
{
|
|
var (organization, _) = await OrganizationTestHelpers.SignUpAsync(_factory,
|
|
PlanType.EnterpriseAnnually, _ownerEmail, passwordManagerSeats: 10,
|
|
paymentMethod: PaymentMethodType.Card);
|
|
organization.UseKeyConnector = true;
|
|
organization.UseSso = true;
|
|
await _organizationRepository.ReplaceAsync(organization);
|
|
|
|
var ssoUserEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com";
|
|
await _factory.LoginWithNewAccount(ssoUserEmail);
|
|
await _loginHelper.LoginAsync(ssoUserEmail);
|
|
|
|
await OrganizationTestHelpers.CreateUserAsync(_factory, organization.Id, ssoUserEmail,
|
|
OrganizationUserType.User, userStatusType: OrganizationUserStatusType.Accepted);
|
|
|
|
var response = await _client.PostAsJsonAsync("/accounts/convert-to-key-connector", new { });
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var user = await _userRepository.GetByEmailAsync(ssoUserEmail);
|
|
Assert.NotNull(user);
|
|
Assert.Null(user.MasterPassword);
|
|
Assert.True(user.UsesKeyConnector);
|
|
Assert.Equal(DateTime.UtcNow, user.RevisionDate, TimeSpan.FromMinutes(1));
|
|
Assert.Equal(DateTime.UtcNow, user.AccountRevisionDate, TimeSpan.FromMinutes(1));
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task RotateV2UserAccountKeysAsync_Success(RotateUserAccountKeysAndDataRequestModel request)
|
|
{
|
|
await _loginHelper.LoginAsync(_ownerEmail);
|
|
var user = await _userRepository.GetByEmailAsync(_ownerEmail);
|
|
if (user == null)
|
|
{
|
|
throw new InvalidOperationException("User not found.");
|
|
}
|
|
|
|
var password = _passwordHasher.HashPassword(user, "newMasterPassword");
|
|
user.MasterPassword = password;
|
|
user.PublicKey = "publicKey";
|
|
user.PrivateKey = _mockEncryptedType7String;
|
|
|
|
await _userRepository.ReplaceAsync(user);
|
|
await _userSignatureKeyPairRepository.CreateAsync(new UserSignatureKeyPair
|
|
{
|
|
UserId = user.Id,
|
|
SignatureAlgorithm = SignatureAlgorithm.Ed25519,
|
|
SigningKey = _mockEncryptedType7String,
|
|
VerifyingKey = "verifyingKey",
|
|
});
|
|
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfType = user.Kdf;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfIterations = user.KdfIterations;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfMemory = user.KdfMemory;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfParallelism = user.KdfParallelism;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.Email = user.Email;
|
|
request.AccountKeys.AccountPublicKey = "publicKey";
|
|
request.AccountKeys.UserKeyEncryptedAccountPrivateKey = _mockEncryptedType7String;
|
|
request.AccountKeys.PublicKeyEncryptionKeyPair = new PublicKeyEncryptionKeyPairRequestModel
|
|
{
|
|
PublicKey = "publicKey",
|
|
WrappedPrivateKey = _mockEncryptedType7String,
|
|
SignedPublicKey = "signedPublicKey",
|
|
};
|
|
request.AccountKeys.SignatureKeyPair = new SignatureKeyPairRequestModel
|
|
{
|
|
SignatureAlgorithm = "ed25519",
|
|
WrappedSigningKey = _mockEncryptedType7String,
|
|
VerifyingKey = "verifyingKey",
|
|
};
|
|
|
|
request.OldMasterKeyAuthenticationHash = "newMasterPassword";
|
|
|
|
request.AccountData.Ciphers =
|
|
[
|
|
new CipherWithIdRequestModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Type = CipherType.Login,
|
|
Name = _mockEncryptedString,
|
|
Login = new CipherLoginModel
|
|
{
|
|
Username = _mockEncryptedString,
|
|
Password = _mockEncryptedString,
|
|
},
|
|
},
|
|
];
|
|
request.AccountData.Folders = [
|
|
new FolderWithIdRequestModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = _mockEncryptedString,
|
|
},
|
|
];
|
|
request.AccountData.Sends = [
|
|
new SendWithIdRequestModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = _mockEncryptedString,
|
|
Key = _mockEncryptedString,
|
|
Disabled = false,
|
|
DeletionDate = DateTime.UtcNow.AddDays(1),
|
|
},
|
|
];
|
|
request.AccountUnlockData.MasterPasswordUnlockData.MasterKeyEncryptedUserKey = _mockEncryptedString;
|
|
request.AccountUnlockData.PasskeyUnlockData = [];
|
|
request.AccountUnlockData.DeviceKeyUnlockData = [];
|
|
request.AccountUnlockData.EmergencyAccessUnlockData = [];
|
|
request.AccountUnlockData.OrganizationAccountRecoveryUnlockData = [];
|
|
|
|
var response = await _client.PostAsJsonAsync("/accounts/key-management/rotate-user-account-keys", request);
|
|
var responseMessage = await response.Content.ReadAsStringAsync();
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var userNewState = await _userRepository.GetByEmailAsync(_ownerEmail);
|
|
Assert.NotNull(userNewState);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.Email, userNewState.Email);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfType, userNewState.Kdf);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfIterations, userNewState.KdfIterations);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfMemory, userNewState.KdfMemory);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfParallelism, userNewState.KdfParallelism);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task RotateUpgradeToV2UserAccountKeysAsync_Success(RotateUserAccountKeysAndDataRequestModel request)
|
|
{
|
|
await _loginHelper.LoginAsync(_ownerEmail);
|
|
var user = await _userRepository.GetByEmailAsync(_ownerEmail);
|
|
if (user == null)
|
|
{
|
|
throw new InvalidOperationException("User not found.");
|
|
}
|
|
|
|
var password = _passwordHasher.HashPassword(user, "newMasterPassword");
|
|
user.MasterPassword = password;
|
|
user.PublicKey = "publicKey";
|
|
user.PrivateKey = _mockEncryptedString;
|
|
|
|
await _userRepository.ReplaceAsync(user);
|
|
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfType = user.Kdf;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfIterations = user.KdfIterations;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfMemory = user.KdfMemory;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.KdfParallelism = user.KdfParallelism;
|
|
request.AccountUnlockData.MasterPasswordUnlockData.Email = user.Email;
|
|
request.AccountKeys.AccountPublicKey = "publicKey";
|
|
request.AccountKeys.UserKeyEncryptedAccountPrivateKey = _mockEncryptedType7String;
|
|
request.AccountKeys.PublicKeyEncryptionKeyPair = new PublicKeyEncryptionKeyPairRequestModel
|
|
{
|
|
PublicKey = "publicKey",
|
|
WrappedPrivateKey = _mockEncryptedType7String,
|
|
SignedPublicKey = "signedPublicKey",
|
|
};
|
|
request.AccountKeys.SignatureKeyPair = new SignatureKeyPairRequestModel
|
|
{
|
|
SignatureAlgorithm = "ed25519",
|
|
WrappedSigningKey = _mockEncryptedType7String,
|
|
VerifyingKey = "verifyingKey",
|
|
};
|
|
request.AccountKeys.SecurityState = new SecurityStateModel
|
|
{
|
|
SecurityVersion = 2,
|
|
SecurityState = "v2",
|
|
};
|
|
|
|
request.OldMasterKeyAuthenticationHash = "newMasterPassword";
|
|
|
|
request.AccountData.Ciphers =
|
|
[
|
|
new CipherWithIdRequestModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Type = CipherType.Login,
|
|
Name = _mockEncryptedString,
|
|
Login = new CipherLoginModel
|
|
{
|
|
Username = _mockEncryptedString,
|
|
Password = _mockEncryptedString,
|
|
},
|
|
},
|
|
];
|
|
request.AccountData.Folders = [
|
|
new FolderWithIdRequestModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = _mockEncryptedString,
|
|
},
|
|
];
|
|
request.AccountData.Sends = [
|
|
new SendWithIdRequestModel
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = _mockEncryptedString,
|
|
Key = _mockEncryptedString,
|
|
Disabled = false,
|
|
DeletionDate = DateTime.UtcNow.AddDays(1),
|
|
},
|
|
];
|
|
request.AccountUnlockData.MasterPasswordUnlockData.MasterKeyEncryptedUserKey = _mockEncryptedString;
|
|
request.AccountUnlockData.PasskeyUnlockData = [];
|
|
request.AccountUnlockData.DeviceKeyUnlockData = [];
|
|
request.AccountUnlockData.EmergencyAccessUnlockData = [];
|
|
request.AccountUnlockData.OrganizationAccountRecoveryUnlockData = [];
|
|
|
|
var response = await _client.PostAsJsonAsync("/accounts/key-management/rotate-user-account-keys", request);
|
|
var responseMessage = await response.Content.ReadAsStringAsync();
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var userNewState = await _userRepository.GetByEmailAsync(_ownerEmail);
|
|
Assert.NotNull(userNewState);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.Email, userNewState.Email);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfType, userNewState.Kdf);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfIterations, userNewState.KdfIterations);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfMemory, userNewState.KdfMemory);
|
|
Assert.Equal(request.AccountUnlockData.MasterPasswordUnlockData.KdfParallelism, userNewState.KdfParallelism);
|
|
}
|
|
}
|