From 6551d9176bfdfb813c1fccf43ee2fbbede01f9af Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Mon, 3 Apr 2023 11:03:59 -0400 Subject: [PATCH 1/2] Modified sso details stored procedure to remove policy checks or an organization (#2831) --- ...ganizationDomainSsoDetailsResponseModel.cs | 2 -- .../OrganizationDomainSsoDetailsData.cs | 6 +---- .../OrganizationDomainRepository.cs | 6 ----- ...ganizationDomainSsoDetails_ReadByEmail.sql | 5 ---- ...PolicyCheckOrganizationDomainSsoDetais.sql | 26 +++++++++++++++++++ 5 files changed, 27 insertions(+), 18 deletions(-) create mode 100644 util/Migrator/DbScripts/2023-03-30_00_RemovePolicyCheckOrganizationDomainSsoDetais.sql diff --git a/src/Api/Models/Response/Organizations/OrganizationDomainSsoDetailsResponseModel.cs b/src/Api/Models/Response/Organizations/OrganizationDomainSsoDetailsResponseModel.cs index 44c4acea9..d995cc5f8 100644 --- a/src/Api/Models/Response/Organizations/OrganizationDomainSsoDetailsResponseModel.cs +++ b/src/Api/Models/Response/Organizations/OrganizationDomainSsoDetailsResponseModel.cs @@ -16,13 +16,11 @@ public class OrganizationDomainSsoDetailsResponseModel : ResponseModel SsoAvailable = data.SsoAvailable; DomainName = data.DomainName; OrganizationIdentifier = data.OrganizationIdentifier; - SsoRequired = data.SsoRequired; VerifiedDate = data.VerifiedDate; } public bool SsoAvailable { get; private set; } public string DomainName { get; private set; } public string OrganizationIdentifier { get; private set; } - public bool SsoRequired { get; private set; } public DateTime? VerifiedDate { get; private set; } } diff --git a/src/Core/Models/Data/Organizations/OrganizationDomainSsoDetailsData.cs b/src/Core/Models/Data/Organizations/OrganizationDomainSsoDetailsData.cs index 1a87db792..b188f9403 100644 --- a/src/Core/Models/Data/Organizations/OrganizationDomainSsoDetailsData.cs +++ b/src/Core/Models/Data/Organizations/OrganizationDomainSsoDetailsData.cs @@ -1,6 +1,4 @@ -using Bit.Core.Enums; - -namespace Bit.Core.Models.Data.Organizations; +namespace Bit.Core.Models.Data.Organizations; public class OrganizationDomainSsoDetailsData { @@ -9,8 +7,6 @@ public class OrganizationDomainSsoDetailsData public string DomainName { get; set; } public bool SsoAvailable { get; set; } public string OrganizationIdentifier { get; set; } - public bool SsoRequired { get; set; } - public PolicyType? PolicyType { get; set; } public DateTime? VerifiedDate { get; set; } public bool OrganizationEnabled { get; set; } } diff --git a/src/Infrastructure.EntityFramework/Repositories/OrganizationDomainRepository.cs b/src/Infrastructure.EntityFramework/Repositories/OrganizationDomainRepository.cs index 8b453d5e5..64438bf70 100644 --- a/src/Infrastructure.EntityFramework/Repositories/OrganizationDomainRepository.cs +++ b/src/Infrastructure.EntityFramework/Repositories/OrganizationDomainRepository.cs @@ -1,6 +1,5 @@ using System.Net.Mail; using AutoMapper; -using Bit.Core.Enums; using Bit.Core.Models.Data.Organizations; using Bit.Core.Repositories; using Bit.Infrastructure.EntityFramework.Models; @@ -78,19 +77,14 @@ public class OrganizationDomainRepository : Repository p.Type == PolicyType.RequireSso) on o.Id - equals p.OrganizationId into pJoin - from p in pJoin.DefaultIfEmpty() where od.DomainName == domainName && o.Enabled select new OrganizationDomainSsoDetailsData { OrganizationId = o.Id, OrganizationName = o.Name, SsoAvailable = o.SsoConfigs.Any(sc => sc.Enabled), - SsoRequired = p != null && p.Enabled, OrganizationIdentifier = o.Identifier, VerifiedDate = od.VerifiedDate, - PolicyType = p.Type, DomainName = od.DomainName }) .AsNoTracking() diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomainSsoDetails_ReadByEmail.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomainSsoDetails_ReadByEmail.sql index b1e4ae767..5cc47213d 100644 --- a/src/Sql/dbo/Stored Procedures/OrganizationDomainSsoDetails_ReadByEmail.sql +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomainSsoDetails_ReadByEmail.sql @@ -12,20 +12,15 @@ BEGIN O.Id AS OrganizationId, O.[Name] AS OrganizationName, S.Enabled AS SsoAvailable, - P.Enabled AS SsoRequired, O.Identifier AS OrganizationIdentifier, OD.VerifiedDate, - P.[Type] AS PolicyType, OD.DomainName FROM [dbo].[OrganizationView] O INNER JOIN [dbo].[OrganizationDomainView] OD ON O.Id = OD.OrganizationId - LEFT JOIN [dbo].[PolicyView] P - ON O.Id = P.OrganizationId LEFT JOIN [dbo].[Ssoconfig] S ON O.Id = S.OrganizationId WHERE OD.DomainName = @Domain AND O.Enabled = 1 - AND (P.Id is NULL OR (P.Id IS NOT NULL AND P.[Type] = 4)) -- SSO Type END \ No newline at end of file diff --git a/util/Migrator/DbScripts/2023-03-30_00_RemovePolicyCheckOrganizationDomainSsoDetais.sql b/util/Migrator/DbScripts/2023-03-30_00_RemovePolicyCheckOrganizationDomainSsoDetais.sql new file mode 100644 index 000000000..4a037c47e --- /dev/null +++ b/util/Migrator/DbScripts/2023-03-30_00_RemovePolicyCheckOrganizationDomainSsoDetais.sql @@ -0,0 +1,26 @@ +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomainSsoDetails_ReadByEmail] + @Email NVARCHAR(256) +AS +BEGIN + SET NOCOUNT ON + + DECLARE @Domain NVARCHAR(256) + +SELECT @Domain = SUBSTRING(@Email, CHARINDEX( '@', @Email) + 1, LEN(@Email)) + +SELECT + O.Id AS OrganizationId, + O.[Name] AS OrganizationName, + S.Enabled AS SsoAvailable, + O.Identifier AS OrganizationIdentifier, + OD.VerifiedDate, + OD.DomainName +FROM + [dbo].[OrganizationView] O +INNER JOIN [dbo].[OrganizationDomainView] OD + ON O.Id = OD.OrganizationId +LEFT JOIN [dbo].[Ssoconfig] S + ON O.Id = S.OrganizationId +WHERE OD.DomainName = @Domain + AND O.Enabled = 1 +END \ No newline at end of file From 49f15d8cc165f7fffbfee2fa0e11390b58c1f854 Mon Sep 17 00:00:00 2001 From: aj-rosado <109146700+aj-rosado@users.noreply.github.com> Date: Wed, 5 Apr 2023 19:18:14 +0100 Subject: [PATCH 2/2] [PS-2390] Updating and adding items into folder and collection on import (#2717) * PS-2390 Adding Id to the Collection/Folder RequestModel replacing folder/collection when they already exist instead of creating a new one Adding items to existing collections if the id matches * PS-2390 Improved Folder/Collection RequestModel code design * PS-2390 Removed whitespaces from FolderRequestModel * PS-2390 Verifying if folder/collection belongs to user/organization when updating or creating a new one * PS-2390 - Removed unnecessary null validation for Id on Folder/CollectionRequestModel * PS-2390 - Added bulk methods to get and update folders at import * PS-2390 - Added bulk methods to get and update collections at import org * PS-2390 - Corrected sqlproj path to Folder_ReadByIdsAndUserId * PS-2390 - Improved code readibility * PS-2390 - Added newlines to EOF * PS-2390 Remove logic to update folders/collections at import * PS-2390 - removed unnecessary methods and imports * PS-2390 - Removed unnecessary formatting change * PS-2390 - Removed unused variable --- .../Accounts/ImportCiphersRequestModel.cs | 2 +- .../Models/Request/CollectionRequestModel.cs | 13 ++++++++- .../ImportOrganizationCiphersRequestModel.cs | 2 +- .../Models/Request/FolderRequestModel.cs | 10 +++++-- .../Services/Implementations/CipherService.cs | 29 +++++++++++++++---- .../Vault/Repositories/CipherRepository.cs | 14 ++++----- .../Vault/Repositories/CipherRepository.cs | 11 +++---- 7 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/Api/Models/Request/Accounts/ImportCiphersRequestModel.cs b/src/Api/Models/Request/Accounts/ImportCiphersRequestModel.cs index 6e99d82dd..30ecedd33 100644 --- a/src/Api/Models/Request/Accounts/ImportCiphersRequestModel.cs +++ b/src/Api/Models/Request/Accounts/ImportCiphersRequestModel.cs @@ -4,7 +4,7 @@ namespace Bit.Api.Models.Request.Accounts; public class ImportCiphersRequestModel { - public FolderRequestModel[] Folders { get; set; } + public FolderWithIdRequestModel[] Folders { get; set; } public CipherRequestModel[] Ciphers { get; set; } public KeyValuePair[] FolderRelationships { get; set; } } diff --git a/src/Api/Models/Request/CollectionRequestModel.cs b/src/Api/Models/Request/CollectionRequestModel.cs index 94b4801f0..abd3d832b 100644 --- a/src/Api/Models/Request/CollectionRequestModel.cs +++ b/src/Api/Models/Request/CollectionRequestModel.cs @@ -23,7 +23,7 @@ public class CollectionRequestModel }); } - public Collection ToCollection(Collection existingCollection) + public virtual Collection ToCollection(Collection existingCollection) { existingCollection.Name = Name; existingCollection.ExternalId = ExternalId; @@ -37,3 +37,14 @@ public class CollectionBulkDeleteRequestModel public IEnumerable Ids { get; set; } public string OrganizationId { get; set; } } + +public class CollectionWithIdRequestModel : CollectionRequestModel +{ + public Guid? Id { get; set; } + + public override Collection ToCollection(Collection existingCollection) + { + existingCollection.Id = Id ?? Guid.Empty; + return base.ToCollection(existingCollection); + } +} diff --git a/src/Api/Models/Request/Organizations/ImportOrganizationCiphersRequestModel.cs b/src/Api/Models/Request/Organizations/ImportOrganizationCiphersRequestModel.cs index 34f765c92..76faa333b 100644 --- a/src/Api/Models/Request/Organizations/ImportOrganizationCiphersRequestModel.cs +++ b/src/Api/Models/Request/Organizations/ImportOrganizationCiphersRequestModel.cs @@ -4,7 +4,7 @@ namespace Bit.Api.Models.Request.Organizations; public class ImportOrganizationCiphersRequestModel { - public CollectionRequestModel[] Collections { get; set; } + public CollectionWithIdRequestModel[] Collections { get; set; } public CipherRequestModel[] Ciphers { get; set; } public KeyValuePair[] CollectionRelationships { get; set; } } diff --git a/src/Api/Vault/Models/Request/FolderRequestModel.cs b/src/Api/Vault/Models/Request/FolderRequestModel.cs index d757c3b64..db9b65099 100644 --- a/src/Api/Vault/Models/Request/FolderRequestModel.cs +++ b/src/Api/Vault/Models/Request/FolderRequestModel.cs @@ -19,7 +19,7 @@ public class FolderRequestModel }); } - public Folder ToFolder(Folder existingFolder) + public virtual Folder ToFolder(Folder existingFolder) { existingFolder.Name = Name; return existingFolder; @@ -28,5 +28,11 @@ public class FolderRequestModel public class FolderWithIdRequestModel : FolderRequestModel { - public Guid Id { get; set; } + public Guid? Id { get; set; } + + public override Folder ToFolder(Folder existingFolder) + { + existingFolder.Id = Id ?? Guid.Empty; + return base.ToFolder(existingFolder); + } } diff --git a/src/Core/Vault/Services/Implementations/CipherService.cs b/src/Core/Vault/Services/Implementations/CipherService.cs index ed1b8e85b..c50f10d8f 100644 --- a/src/Core/Vault/Services/Implementations/CipherService.cs +++ b/src/Core/Vault/Services/Implementations/CipherService.cs @@ -648,10 +648,18 @@ public class CipherService : ICipherService } } - // Init. ids for folders + var userfoldersIds = (await _folderRepository.GetManyByUserIdAsync(userId ?? Guid.Empty)).Select(f => f.Id).ToList(); + + //Assign id to the ones that don't exist in DB + //Need to keep the list order to create the relationships + List newFolders = new List(); foreach (var folder in folders) { - folder.SetNewId(); + if (!userfoldersIds.Contains(folder.Id)) + { + folder.SetNewId(); + newFolders.Add(folder); + } } // Create the folder associations based on the newly created folder ids @@ -670,7 +678,7 @@ public class CipherService : ICipherService } // Create it all - await _cipherRepository.CreateAsync(ciphers, folders); + await _cipherRepository.CreateAsync(ciphers, newFolders); // push if (userId.HasValue) @@ -705,10 +713,19 @@ public class CipherService : ICipherService cipher.SetNewId(); } - // Init. ids for collections + var userCollectionsIds = (await _collectionRepository.GetManyByOrganizationIdAsync(org.Id)).Select(c => c.Id).ToList(); + + //Assign id to the ones that don't exist in DB + //Need to keep the list order to create the relationships + List newCollections = new List(); + foreach (var collection in collections) { - collection.SetNewId(); + if (!userCollectionsIds.Contains(collection.Id)) + { + collection.SetNewId(); + newCollections.Add(collection); + } } // Create associations based on the newly assigned ids @@ -731,7 +748,7 @@ public class CipherService : ICipherService } // Create it all - await _cipherRepository.CreateAsync(ciphers, collections, collectionCiphers); + await _cipherRepository.CreateAsync(ciphers, newCollections, collectionCiphers); // push await _pushService.PushSyncVaultAsync(importingUserId); diff --git a/src/Infrastructure.Dapper/Vault/Repositories/CipherRepository.cs b/src/Infrastructure.Dapper/Vault/Repositories/CipherRepository.cs index aa2d12445..6b7ff9771 100644 --- a/src/Infrastructure.Dapper/Vault/Repositories/CipherRepository.cs +++ b/src/Infrastructure.Dapper/Vault/Repositories/CipherRepository.cs @@ -616,15 +616,15 @@ public class CipherRepository : Repository, ICipherRepository var dataTable = BuildCollectionsTable(bulkCopy, collections); bulkCopy.WriteToServer(dataTable); } + } - if (collectionCiphers.Any()) + if (collectionCiphers.Any()) + { + using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction)) { - using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction)) - { - bulkCopy.DestinationTableName = "[dbo].[CollectionCipher]"; - var dataTable = BuildCollectionCiphersTable(bulkCopy, collectionCiphers); - bulkCopy.WriteToServer(dataTable); - } + bulkCopy.DestinationTableName = "[dbo].[CollectionCipher]"; + var dataTable = BuildCollectionCiphersTable(bulkCopy, collectionCiphers); + bulkCopy.WriteToServer(dataTable); } } diff --git a/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs b/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs index a435859da..fa847ebae 100644 --- a/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs +++ b/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs @@ -168,16 +168,17 @@ public class CipherRepository : Repository>(ciphers); await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, cipherEntities); + if (collections.Any()) { var collectionEntities = Mapper.Map>(collections); await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, collectionEntities); + } - if (collectionCiphers.Any()) - { - var collectionCipherEntities = Mapper.Map>(collectionCiphers); - await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, collectionCipherEntities); - } + if (collectionCiphers.Any()) + { + var collectionCipherEntities = Mapper.Map>(collectionCiphers); + await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, collectionCipherEntities); } await dbContext.UserBumpAccountRevisionDateByOrganizationIdAsync(ciphers.First().OrganizationId.Value); await dbContext.SaveChangesAsync();