1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-02 00:22:50 -05:00

Merge branch 'feature/billing-obfuscation' into AC-432-add-existing-organization-flow-server-admin-portal-database

This commit is contained in:
Rui Tome
2023-04-06 12:27:33 +01:00
12 changed files with 85 additions and 41 deletions

View File

@ -4,7 +4,7 @@ namespace Bit.Api.Models.Request.Accounts;
public class ImportCiphersRequestModel public class ImportCiphersRequestModel
{ {
public FolderRequestModel[] Folders { get; set; } public FolderWithIdRequestModel[] Folders { get; set; }
public CipherRequestModel[] Ciphers { get; set; } public CipherRequestModel[] Ciphers { get; set; }
public KeyValuePair<int, int>[] FolderRelationships { get; set; } public KeyValuePair<int, int>[] FolderRelationships { get; set; }
} }

View File

@ -23,7 +23,7 @@ public class CollectionRequestModel
}); });
} }
public Collection ToCollection(Collection existingCollection) public virtual Collection ToCollection(Collection existingCollection)
{ {
existingCollection.Name = Name; existingCollection.Name = Name;
existingCollection.ExternalId = ExternalId; existingCollection.ExternalId = ExternalId;
@ -37,3 +37,14 @@ public class CollectionBulkDeleteRequestModel
public IEnumerable<string> Ids { get; set; } public IEnumerable<string> Ids { get; set; }
public string OrganizationId { 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);
}
}

View File

@ -4,7 +4,7 @@ namespace Bit.Api.Models.Request.Organizations;
public class ImportOrganizationCiphersRequestModel public class ImportOrganizationCiphersRequestModel
{ {
public CollectionRequestModel[] Collections { get; set; } public CollectionWithIdRequestModel[] Collections { get; set; }
public CipherRequestModel[] Ciphers { get; set; } public CipherRequestModel[] Ciphers { get; set; }
public KeyValuePair<int, int>[] CollectionRelationships { get; set; } public KeyValuePair<int, int>[] CollectionRelationships { get; set; }
} }

View File

@ -16,13 +16,11 @@ public class OrganizationDomainSsoDetailsResponseModel : ResponseModel
SsoAvailable = data.SsoAvailable; SsoAvailable = data.SsoAvailable;
DomainName = data.DomainName; DomainName = data.DomainName;
OrganizationIdentifier = data.OrganizationIdentifier; OrganizationIdentifier = data.OrganizationIdentifier;
SsoRequired = data.SsoRequired;
VerifiedDate = data.VerifiedDate; VerifiedDate = data.VerifiedDate;
} }
public bool SsoAvailable { get; private set; } public bool SsoAvailable { get; private set; }
public string DomainName { get; private set; } public string DomainName { get; private set; }
public string OrganizationIdentifier { get; private set; } public string OrganizationIdentifier { get; private set; }
public bool SsoRequired { get; private set; }
public DateTime? VerifiedDate { get; private set; } public DateTime? VerifiedDate { get; private set; }
} }

View File

@ -19,7 +19,7 @@ public class FolderRequestModel
}); });
} }
public Folder ToFolder(Folder existingFolder) public virtual Folder ToFolder(Folder existingFolder)
{ {
existingFolder.Name = Name; existingFolder.Name = Name;
return existingFolder; return existingFolder;
@ -28,5 +28,11 @@ public class FolderRequestModel
public class FolderWithIdRequestModel : 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);
}
} }

View File

@ -1,6 +1,4 @@
using Bit.Core.Enums; namespace Bit.Core.Models.Data.Organizations;
namespace Bit.Core.Models.Data.Organizations;
public class OrganizationDomainSsoDetailsData public class OrganizationDomainSsoDetailsData
{ {
@ -9,8 +7,6 @@ public class OrganizationDomainSsoDetailsData
public string DomainName { get; set; } public string DomainName { get; set; }
public bool SsoAvailable { get; set; } public bool SsoAvailable { get; set; }
public string OrganizationIdentifier { get; set; } public string OrganizationIdentifier { get; set; }
public bool SsoRequired { get; set; }
public PolicyType? PolicyType { get; set; }
public DateTime? VerifiedDate { get; set; } public DateTime? VerifiedDate { get; set; }
public bool OrganizationEnabled { get; set; } public bool OrganizationEnabled { get; set; }
} }

View File

@ -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<Folder> newFolders = new List<Folder>();
foreach (var folder in folders) 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 // Create the folder associations based on the newly created folder ids
@ -670,7 +678,7 @@ public class CipherService : ICipherService
} }
// Create it all // Create it all
await _cipherRepository.CreateAsync(ciphers, folders); await _cipherRepository.CreateAsync(ciphers, newFolders);
// push // push
if (userId.HasValue) if (userId.HasValue)
@ -705,10 +713,19 @@ public class CipherService : ICipherService
cipher.SetNewId(); 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<Collection> newCollections = new List<Collection>();
foreach (var collection in collections) 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 // Create associations based on the newly assigned ids
@ -731,7 +748,7 @@ public class CipherService : ICipherService
} }
// Create it all // Create it all
await _cipherRepository.CreateAsync(ciphers, collections, collectionCiphers); await _cipherRepository.CreateAsync(ciphers, newCollections, collectionCiphers);
// push // push
await _pushService.PushSyncVaultAsync(importingUserId); await _pushService.PushSyncVaultAsync(importingUserId);

View File

@ -616,15 +616,15 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
var dataTable = BuildCollectionsTable(bulkCopy, collections); var dataTable = BuildCollectionsTable(bulkCopy, collections);
bulkCopy.WriteToServer(dataTable); 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.DestinationTableName = "[dbo].[CollectionCipher]"; bulkCopy.WriteToServer(dataTable);
var dataTable = BuildCollectionCiphersTable(bulkCopy, collectionCiphers);
bulkCopy.WriteToServer(dataTable);
}
} }
} }

View File

@ -1,6 +1,5 @@
using System.Net.Mail; using System.Net.Mail;
using AutoMapper; using AutoMapper;
using Bit.Core.Enums;
using Bit.Core.Models.Data.Organizations; using Bit.Core.Models.Data.Organizations;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Infrastructure.EntityFramework.Models; using Bit.Infrastructure.EntityFramework.Models;
@ -78,19 +77,14 @@ public class OrganizationDomainRepository : Repository<Core.Entities.Organizatio
from od in o.Domains from od in o.Domains
join s in dbContext.SsoConfigs on o.Id equals s.OrganizationId into sJoin join s in dbContext.SsoConfigs on o.Id equals s.OrganizationId into sJoin
from s in sJoin.DefaultIfEmpty() from s in sJoin.DefaultIfEmpty()
join p in dbContext.Policies.Where(p => p.Type == PolicyType.RequireSso) on o.Id
equals p.OrganizationId into pJoin
from p in pJoin.DefaultIfEmpty()
where od.DomainName == domainName && o.Enabled where od.DomainName == domainName && o.Enabled
select new OrganizationDomainSsoDetailsData select new OrganizationDomainSsoDetailsData
{ {
OrganizationId = o.Id, OrganizationId = o.Id,
OrganizationName = o.Name, OrganizationName = o.Name,
SsoAvailable = o.SsoConfigs.Any(sc => sc.Enabled), SsoAvailable = o.SsoConfigs.Any(sc => sc.Enabled),
SsoRequired = p != null && p.Enabled,
OrganizationIdentifier = o.Identifier, OrganizationIdentifier = o.Identifier,
VerifiedDate = od.VerifiedDate, VerifiedDate = od.VerifiedDate,
PolicyType = p.Type,
DomainName = od.DomainName DomainName = od.DomainName
}) })
.AsNoTracking() .AsNoTracking()

View File

@ -168,16 +168,17 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
var dbContext = GetDatabaseContext(scope); var dbContext = GetDatabaseContext(scope);
var cipherEntities = Mapper.Map<List<Cipher>>(ciphers); var cipherEntities = Mapper.Map<List<Cipher>>(ciphers);
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, cipherEntities); await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, cipherEntities);
if (collections.Any()) if (collections.Any())
{ {
var collectionEntities = Mapper.Map<List<Collection>>(collections); var collectionEntities = Mapper.Map<List<Collection>>(collections);
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, collectionEntities); await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, collectionEntities);
}
if (collectionCiphers.Any()) if (collectionCiphers.Any())
{ {
var collectionCipherEntities = Mapper.Map<List<CollectionCipher>>(collectionCiphers); var collectionCipherEntities = Mapper.Map<List<CollectionCipher>>(collectionCiphers);
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, collectionCipherEntities); await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, collectionCipherEntities);
}
} }
await dbContext.UserBumpAccountRevisionDateByOrganizationIdAsync(ciphers.First().OrganizationId.Value); await dbContext.UserBumpAccountRevisionDateByOrganizationIdAsync(ciphers.First().OrganizationId.Value);
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();

View File

@ -12,20 +12,15 @@ BEGIN
O.Id AS OrganizationId, O.Id AS OrganizationId,
O.[Name] AS OrganizationName, O.[Name] AS OrganizationName,
S.Enabled AS SsoAvailable, S.Enabled AS SsoAvailable,
P.Enabled AS SsoRequired,
O.Identifier AS OrganizationIdentifier, O.Identifier AS OrganizationIdentifier,
OD.VerifiedDate, OD.VerifiedDate,
P.[Type] AS PolicyType,
OD.DomainName OD.DomainName
FROM FROM
[dbo].[OrganizationView] O [dbo].[OrganizationView] O
INNER JOIN [dbo].[OrganizationDomainView] OD INNER JOIN [dbo].[OrganizationDomainView] OD
ON O.Id = OD.OrganizationId ON O.Id = OD.OrganizationId
LEFT JOIN [dbo].[PolicyView] P
ON O.Id = P.OrganizationId
LEFT JOIN [dbo].[Ssoconfig] S LEFT JOIN [dbo].[Ssoconfig] S
ON O.Id = S.OrganizationId ON O.Id = S.OrganizationId
WHERE OD.DomainName = @Domain WHERE OD.DomainName = @Domain
AND O.Enabled = 1 AND O.Enabled = 1
AND (P.Id is NULL OR (P.Id IS NOT NULL AND P.[Type] = 4)) -- SSO Type
END END

View File

@ -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