mirror of
https://github.com/bitwarden/server.git
synced 2025-07-02 16:42:50 -05:00
[PM-19883] Add untrust devices endpoint (#5619)
* Add untrust devices endpoint * Fix tests * Update src/Core/Auth/UserFeatures/DeviceTrust/UntrustDevicesCommand.cs Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> * Fix whitespace --------- Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com>
This commit is contained in:
11
src/Api/Auth/Models/Request/UntrustDevicesModel.cs
Normal file
11
src/Api/Auth/Models/Request/UntrustDevicesModel.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Api.Auth.Models.Request;
|
||||
|
||||
public class UntrustDevicesRequestModel
|
||||
{
|
||||
[Required]
|
||||
public IEnumerable<Guid> Devices { get; set; } = null!;
|
||||
}
|
@ -4,6 +4,7 @@ using Bit.Api.Models.Request;
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Core.Auth.Models.Api.Request;
|
||||
using Bit.Core.Auth.Models.Api.Response;
|
||||
using Bit.Core.Auth.UserFeatures.DeviceTrust;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
@ -21,6 +22,7 @@ public class DevicesController : Controller
|
||||
private readonly IDeviceRepository _deviceRepository;
|
||||
private readonly IDeviceService _deviceService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IUntrustDevicesCommand _untrustDevicesCommand;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly ILogger<DevicesController> _logger;
|
||||
@ -29,6 +31,7 @@ public class DevicesController : Controller
|
||||
IDeviceRepository deviceRepository,
|
||||
IDeviceService deviceService,
|
||||
IUserService userService,
|
||||
IUntrustDevicesCommand untrustDevicesCommand,
|
||||
IUserRepository userRepository,
|
||||
ICurrentContext currentContext,
|
||||
ILogger<DevicesController> logger)
|
||||
@ -36,6 +39,7 @@ public class DevicesController : Controller
|
||||
_deviceRepository = deviceRepository;
|
||||
_deviceService = deviceService;
|
||||
_userService = userService;
|
||||
_untrustDevicesCommand = untrustDevicesCommand;
|
||||
_userRepository = userRepository;
|
||||
_currentContext = currentContext;
|
||||
_logger = logger;
|
||||
@ -165,6 +169,19 @@ public class DevicesController : Controller
|
||||
model.OtherDevices ?? Enumerable.Empty<OtherDeviceKeysUpdateRequestModel>());
|
||||
}
|
||||
|
||||
[HttpPost("untrust")]
|
||||
public async Task PostUntrust([FromBody] UntrustDevicesRequestModel model)
|
||||
{
|
||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
await _untrustDevicesCommand.UntrustDevices(user, model.Devices);
|
||||
}
|
||||
|
||||
[HttpPut("identifier/{identifier}/token")]
|
||||
[HttpPost("identifier/{identifier}/token")]
|
||||
public async Task PutToken(string identifier, [FromBody] DeviceTokenRequestModel model)
|
||||
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.Auth.UserFeatures.DeviceTrust;
|
||||
|
||||
public interface IUntrustDevicesCommand
|
||||
{
|
||||
public Task UntrustDevices(User user, IEnumerable<Guid> devicesToUntrust);
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.Auth.UserFeatures.DeviceTrust;
|
||||
|
||||
public class UntrustDevicesCommand : IUntrustDevicesCommand
|
||||
{
|
||||
private readonly IDeviceRepository _deviceRepository;
|
||||
|
||||
public UntrustDevicesCommand(
|
||||
IDeviceRepository deviceRepository)
|
||||
{
|
||||
_deviceRepository = deviceRepository;
|
||||
}
|
||||
|
||||
public async Task UntrustDevices(User user, IEnumerable<Guid> devicesToUntrust)
|
||||
{
|
||||
var userDevices = await _deviceRepository.GetManyByUserIdAsync(user.Id);
|
||||
var deviceIdDict = userDevices.ToDictionary(device => device.Id);
|
||||
|
||||
// Validate that the user owns all devices that they passed in
|
||||
foreach (var deviceId in devicesToUntrust)
|
||||
{
|
||||
if (!deviceIdDict.ContainsKey(deviceId))
|
||||
{
|
||||
throw new UnauthorizedAccessException($"User {user.Id} does not have access to device {deviceId}");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var deviceId in devicesToUntrust)
|
||||
{
|
||||
var device = deviceIdDict[deviceId];
|
||||
device.EncryptedPrivateKey = null;
|
||||
device.EncryptedPublicKey = null;
|
||||
device.EncryptedUserKey = null;
|
||||
await _deviceRepository.UpsertAsync(device);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
|
||||
|
||||
using Bit.Core.Auth.UserFeatures.DeviceTrust;
|
||||
using Bit.Core.Auth.UserFeatures.Registration;
|
||||
using Bit.Core.Auth.UserFeatures.Registration.Implementations;
|
||||
using Bit.Core.Auth.UserFeatures.TdeOffboardingPassword.Interfaces;
|
||||
@ -22,6 +23,7 @@ public static class UserServiceCollectionExtensions
|
||||
public static void AddUserServices(this IServiceCollection services, IGlobalSettings globalSettings)
|
||||
{
|
||||
services.AddScoped<IUserService, UserService>();
|
||||
services.AddDeviceTrustCommands();
|
||||
services.AddUserPasswordCommands();
|
||||
services.AddUserRegistrationCommands();
|
||||
services.AddWebAuthnLoginCommands();
|
||||
@ -29,6 +31,11 @@ public static class UserServiceCollectionExtensions
|
||||
services.AddTwoFactorQueries();
|
||||
}
|
||||
|
||||
public static void AddDeviceTrustCommands(this IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<IUntrustDevicesCommand, UntrustDevicesCommand>();
|
||||
}
|
||||
|
||||
public static void AddUserKeyCommands(this IServiceCollection services, IGlobalSettings globalSettings)
|
||||
{
|
||||
services.AddScoped<IRotateUserKeyCommand, RotateUserKeyCommand>();
|
||||
|
Reference in New Issue
Block a user