mirror of
https://github.com/bitwarden/server.git
synced 2024-11-22 12:15:36 +01:00
[PM-7029] Remove conditional logic for KeyRotationImprovements feature flag (#4002)
* Removed business logic that references flag * Removed using statement. * Undid accidental keystroke. * Removed unused method. * Removed unused imports.
This commit is contained in:
parent
479f8319c2
commit
7f9d7c0c5d
@ -43,7 +43,6 @@ using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.Auth.Controllers;
|
||||
@ -438,59 +437,19 @@ public class AccountsController : Controller
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
IdentityResult result;
|
||||
if (_featureService.IsEnabled(FeatureFlagKeys.KeyRotationImprovements))
|
||||
var dataModel = new RotateUserKeyData
|
||||
{
|
||||
var dataModel = new RotateUserKeyData
|
||||
{
|
||||
MasterPasswordHash = model.MasterPasswordHash,
|
||||
Key = model.Key,
|
||||
PrivateKey = model.PrivateKey,
|
||||
Ciphers = await _cipherValidator.ValidateAsync(user, model.Ciphers),
|
||||
Folders = await _folderValidator.ValidateAsync(user, model.Folders),
|
||||
Sends = await _sendValidator.ValidateAsync(user, model.Sends),
|
||||
EmergencyAccesses = await _emergencyAccessValidator.ValidateAsync(user, model.EmergencyAccessKeys),
|
||||
OrganizationUsers = await _organizationUserValidator.ValidateAsync(user, model.ResetPasswordKeys)
|
||||
};
|
||||
|
||||
result = await _rotateUserKeyCommand.RotateUserKeyAsync(user, dataModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ciphers = new List<Cipher>();
|
||||
if (model.Ciphers.Any())
|
||||
{
|
||||
var existingCiphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, useFlexibleCollections: UseFlexibleCollections);
|
||||
ciphers.AddRange(existingCiphers
|
||||
.Join(model.Ciphers, c => c.Id, c => c.Id, (existing, c) => c.ToCipher(existing)));
|
||||
}
|
||||
|
||||
var folders = new List<Folder>();
|
||||
if (model.Folders.Any())
|
||||
{
|
||||
var existingFolders = await _folderRepository.GetManyByUserIdAsync(user.Id);
|
||||
folders.AddRange(existingFolders
|
||||
.Join(model.Folders, f => f.Id, f => f.Id, (existing, f) => f.ToFolder(existing)));
|
||||
}
|
||||
|
||||
var sends = new List<Send>();
|
||||
if (model.Sends?.Any() == true)
|
||||
{
|
||||
var existingSends = await _sendRepository.GetManyByUserIdAsync(user.Id);
|
||||
sends.AddRange(existingSends
|
||||
.Join(model.Sends, s => s.Id, s => s.Id, (existing, s) => s.ToSend(existing, _sendService)));
|
||||
}
|
||||
|
||||
result = await _userService.UpdateKeyAsync(
|
||||
user,
|
||||
model.MasterPasswordHash,
|
||||
model.Key,
|
||||
model.PrivateKey,
|
||||
ciphers,
|
||||
folders,
|
||||
sends);
|
||||
}
|
||||
MasterPasswordHash = model.MasterPasswordHash,
|
||||
Key = model.Key,
|
||||
PrivateKey = model.PrivateKey,
|
||||
Ciphers = await _cipherValidator.ValidateAsync(user, model.Ciphers),
|
||||
Folders = await _folderValidator.ValidateAsync(user, model.Folders),
|
||||
Sends = await _sendValidator.ValidateAsync(user, model.Sends),
|
||||
EmergencyAccesses = await _emergencyAccessValidator.ValidateAsync(user, model.EmergencyAccessKeys),
|
||||
OrganizationUsers = await _organizationUserValidator.ValidateAsync(user, model.ResetPasswordKeys)
|
||||
};
|
||||
|
||||
var result = await _rotateUserKeyCommand.RotateUserKeyAsync(user, dataModel);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ using Bit.Core.Auth.Models;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Fido2NetLib;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
@ -39,8 +37,6 @@ public interface IUserService
|
||||
Task<IdentityResult> UpdateTempPasswordAsync(User user, string newMasterPassword, string key, string hint);
|
||||
Task<IdentityResult> ChangeKdfAsync(User user, string masterPassword, string newMasterPassword, string key,
|
||||
KdfType kdf, int kdfIterations, int? kdfMemory, int? kdfParallelism);
|
||||
Task<IdentityResult> UpdateKeyAsync(User user, string masterPassword, string key, string privateKey,
|
||||
IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders, IEnumerable<Send> sends);
|
||||
Task<IdentityResult> RefreshSecurityStampAsync(User user, string masterPasswordHash);
|
||||
Task UpdateTwoFactorProviderAsync(User user, TwoFactorProviderType type, bool setEnabled = true, bool logEvent = true);
|
||||
Task DisableTwoFactorProviderAsync(User user, TwoFactorProviderType type,
|
||||
|
@ -14,12 +14,10 @@ using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tokens;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Business;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
using Fido2NetLib;
|
||||
using Fido2NetLib.Objects;
|
||||
@ -862,39 +860,6 @@ public class UserService : UserManager<User>, IUserService, IDisposable
|
||||
return IdentityResult.Failed(_identityErrorDescriber.PasswordMismatch());
|
||||
}
|
||||
|
||||
public async Task<IdentityResult> UpdateKeyAsync(User user, string masterPassword, string key, string privateKey,
|
||||
IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders, IEnumerable<Send> sends)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
if (await CheckPasswordAsync(user, masterPassword))
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
user.RevisionDate = user.AccountRevisionDate = now;
|
||||
user.LastKeyRotationDate = now;
|
||||
user.SecurityStamp = Guid.NewGuid().ToString();
|
||||
user.Key = key;
|
||||
user.PrivateKey = privateKey;
|
||||
if (ciphers.Any() || folders.Any() || sends.Any())
|
||||
{
|
||||
await _cipherRepository.UpdateUserKeysAndCiphersAsync(user, ciphers, folders, sends);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _userRepository.ReplaceAsync(user);
|
||||
}
|
||||
|
||||
await _pushService.PushLogOutAsync(user.Id, excludeCurrentContextFromPush: true);
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
Logger.LogWarning("Update key failed for user {userId}.", user.Id);
|
||||
return IdentityResult.Failed(_identityErrorDescriber.PasswordMismatch());
|
||||
}
|
||||
|
||||
public async Task<IdentityResult> RefreshSecurityStampAsync(User user, string secret)
|
||||
{
|
||||
if (user == null)
|
||||
|
@ -1,7 +1,6 @@
|
||||
using Bit.Core.Auth.UserFeatures.UserKey;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Models.Data;
|
||||
|
||||
@ -30,7 +29,6 @@ public interface ICipherRepository : IRepository<Cipher, Guid>
|
||||
Task MoveAsync(IEnumerable<Guid> ids, Guid? folderId, Guid userId, bool useFlexibleCollections);
|
||||
Task DeleteByUserIdAsync(Guid userId);
|
||||
Task DeleteByOrganizationIdAsync(Guid organizationId);
|
||||
Task UpdateUserKeysAndCiphersAsync(User user, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders, IEnumerable<Send> sends);
|
||||
Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers);
|
||||
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
|
||||
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
|
||||
|
@ -380,170 +380,6 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
||||
};
|
||||
}
|
||||
|
||||
public Task UpdateUserKeysAndCiphersAsync(User user, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders, IEnumerable<Send> sends)
|
||||
{
|
||||
using (var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
using (var transaction = connection.BeginTransaction())
|
||||
{
|
||||
try
|
||||
{
|
||||
// 1. Update user.
|
||||
|
||||
using (var cmd = new SqlCommand("[dbo].[User_UpdateKeys]", connection, transaction))
|
||||
{
|
||||
cmd.CommandType = CommandType.StoredProcedure;
|
||||
cmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = user.Id;
|
||||
cmd.Parameters.Add("@SecurityStamp", SqlDbType.NVarChar).Value = user.SecurityStamp;
|
||||
cmd.Parameters.Add("@Key", SqlDbType.VarChar).Value = user.Key;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(user.PrivateKey))
|
||||
{
|
||||
cmd.Parameters.Add("@PrivateKey", SqlDbType.VarChar).Value = DBNull.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.Parameters.Add("@PrivateKey", SqlDbType.VarChar).Value = user.PrivateKey;
|
||||
}
|
||||
|
||||
cmd.Parameters.Add("@RevisionDate", SqlDbType.DateTime2).Value = user.RevisionDate;
|
||||
cmd.Parameters.Add("@AccountRevisionDate", SqlDbType.DateTime2).Value = user.AccountRevisionDate;
|
||||
cmd.Parameters.Add("@LastKeyRotationDate", SqlDbType.DateTime2).Value = user.LastKeyRotationDate;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
// 2. Create temp tables to bulk copy into.
|
||||
|
||||
var sqlCreateTemp = @"
|
||||
SELECT TOP 0 *
|
||||
INTO #TempCipher
|
||||
FROM [dbo].[Cipher]
|
||||
|
||||
SELECT TOP 0 *
|
||||
INTO #TempFolder
|
||||
FROM [dbo].[Folder]
|
||||
|
||||
SELECT TOP 0 *
|
||||
INTO #TempSend
|
||||
FROM [dbo].[Send]";
|
||||
|
||||
using (var cmd = new SqlCommand(sqlCreateTemp, connection, transaction))
|
||||
{
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
// 3. Bulk copy into temp tables.
|
||||
|
||||
if (ciphers.Any())
|
||||
{
|
||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
||||
{
|
||||
bulkCopy.DestinationTableName = "#TempCipher";
|
||||
var dataTable = BuildCiphersTable(bulkCopy, ciphers);
|
||||
bulkCopy.WriteToServer(dataTable);
|
||||
}
|
||||
}
|
||||
|
||||
if (folders.Any())
|
||||
{
|
||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
||||
{
|
||||
bulkCopy.DestinationTableName = "#TempFolder";
|
||||
var dataTable = BuildFoldersTable(bulkCopy, folders);
|
||||
bulkCopy.WriteToServer(dataTable);
|
||||
}
|
||||
}
|
||||
|
||||
if (sends.Any())
|
||||
{
|
||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
||||
{
|
||||
bulkCopy.DestinationTableName = "#TempSend";
|
||||
var dataTable = BuildSendsTable(bulkCopy, sends);
|
||||
bulkCopy.WriteToServer(dataTable);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Insert into real tables from temp tables and clean up.
|
||||
|
||||
var sql = string.Empty;
|
||||
|
||||
if (ciphers.Any())
|
||||
{
|
||||
sql += @"
|
||||
UPDATE
|
||||
[dbo].[Cipher]
|
||||
SET
|
||||
[Data] = TC.[Data],
|
||||
[Attachments] = TC.[Attachments],
|
||||
[RevisionDate] = TC.[RevisionDate],
|
||||
[Key] = TC.[Key]
|
||||
FROM
|
||||
[dbo].[Cipher] C
|
||||
INNER JOIN
|
||||
#TempCipher TC ON C.Id = TC.Id
|
||||
WHERE
|
||||
C.[UserId] = @UserId";
|
||||
}
|
||||
|
||||
if (folders.Any())
|
||||
{
|
||||
sql += @"
|
||||
UPDATE
|
||||
[dbo].[Folder]
|
||||
SET
|
||||
[Name] = TF.[Name],
|
||||
[RevisionDate] = TF.[RevisionDate]
|
||||
FROM
|
||||
[dbo].[Folder] F
|
||||
INNER JOIN
|
||||
#TempFolder TF ON F.Id = TF.Id
|
||||
WHERE
|
||||
F.[UserId] = @UserId";
|
||||
}
|
||||
|
||||
if (sends.Any())
|
||||
{
|
||||
sql += @"
|
||||
UPDATE
|
||||
[dbo].[Send]
|
||||
SET
|
||||
[Key] = TS.[Key],
|
||||
[RevisionDate] = TS.[RevisionDate]
|
||||
FROM
|
||||
[dbo].[Send] S
|
||||
INNER JOIN
|
||||
#TempSend TS ON S.Id = TS.Id
|
||||
WHERE
|
||||
S.[UserId] = @UserId";
|
||||
}
|
||||
|
||||
sql += @"
|
||||
DROP TABLE #TempCipher
|
||||
DROP TABLE #TempFolder
|
||||
DROP TABLE #TempSend";
|
||||
|
||||
using (var cmd = new SqlCommand(sql, connection, transaction))
|
||||
{
|
||||
cmd.Parameters.Add("@UserId", SqlDbType.UniqueIdentifier).Value = user.Id;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public async Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers)
|
||||
{
|
||||
if (!ciphers.Any())
|
||||
|
@ -19,7 +19,6 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NS = Newtonsoft.Json;
|
||||
using NSL = Newtonsoft.Json.Linq;
|
||||
using User = Bit.Core.Entities.User;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Vault.Repositories;
|
||||
|
||||
@ -865,23 +864,6 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public async Task UpdateUserKeysAndCiphersAsync(User user, IEnumerable<Core.Vault.Entities.Cipher> ciphers, IEnumerable<Core.Vault.Entities.Folder> folders, IEnumerable<Core.Tools.Entities.Send> sends)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
await UserUpdateKeys(user);
|
||||
var cipherEntities = Mapper.Map<List<Cipher>>(ciphers);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, cipherEntities);
|
||||
var folderEntities = Mapper.Map<List<Folder>>(folders);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, folderEntities);
|
||||
var sendEntities = Mapper.Map<List<Send>>(sends);
|
||||
await dbContext.BulkCopyAsync(base.DefaultBulkCopyOptions, sendEntities);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpsertAsync(CipherDetails cipher)
|
||||
{
|
||||
if (cipher.Id.Equals(default))
|
||||
|
Loading…
Reference in New Issue
Block a user