mirror of
https://github.com/bitwarden/server.git
synced 2024-11-21 12:05:42 +01:00
[PM-11408] domain verification stat in portal and add cs delete permission (#4943)
* Add delete permission to cs role * Add domain verification stat to portal * add feature flag and unit tests * fix test * Refactor from PR feedback * update comment
This commit is contained in:
parent
6cc097ec49
commit
359c2787ad
@ -4,6 +4,7 @@ using Bit.Admin.Enums;
|
|||||||
using Bit.Admin.Models;
|
using Bit.Admin.Models;
|
||||||
using Bit.Admin.Services;
|
using Bit.Admin.Services;
|
||||||
using Bit.Admin.Utilities;
|
using Bit.Admin.Utilities;
|
||||||
|
using Bit.Core;
|
||||||
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
@ -24,6 +25,8 @@ public class UsersController : Controller
|
|||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
private readonly IAccessControlService _accessControlService;
|
private readonly IAccessControlService _accessControlService;
|
||||||
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
|
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
private readonly IFeatureService _featureService;
|
||||||
|
|
||||||
public UsersController(
|
public UsersController(
|
||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
@ -31,7 +34,9 @@ public class UsersController : Controller
|
|||||||
IPaymentService paymentService,
|
IPaymentService paymentService,
|
||||||
GlobalSettings globalSettings,
|
GlobalSettings globalSettings,
|
||||||
IAccessControlService accessControlService,
|
IAccessControlService accessControlService,
|
||||||
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery)
|
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
|
||||||
|
IUserService userService,
|
||||||
|
IFeatureService featureService)
|
||||||
{
|
{
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
_cipherRepository = cipherRepository;
|
_cipherRepository = cipherRepository;
|
||||||
@ -39,6 +44,8 @@ public class UsersController : Controller
|
|||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
_accessControlService = accessControlService;
|
_accessControlService = accessControlService;
|
||||||
_twoFactorIsEnabledQuery = twoFactorIsEnabledQuery;
|
_twoFactorIsEnabledQuery = twoFactorIsEnabledQuery;
|
||||||
|
_userService = userService;
|
||||||
|
_featureService = featureService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[RequirePermission(Permission.User_List_View)]
|
[RequirePermission(Permission.User_List_View)]
|
||||||
@ -82,8 +89,8 @@ public class UsersController : Controller
|
|||||||
var ciphers = await _cipherRepository.GetManyByUserIdAsync(id);
|
var ciphers = await _cipherRepository.GetManyByUserIdAsync(id);
|
||||||
|
|
||||||
var isTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(user);
|
var isTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(user);
|
||||||
|
var verifiedDomain = await AccountDeprovisioningEnabled(user.Id);
|
||||||
return View(UserViewModel.MapViewModel(user, isTwoFactorEnabled, ciphers));
|
return View(UserViewModel.MapViewModel(user, isTwoFactorEnabled, ciphers, verifiedDomain));
|
||||||
}
|
}
|
||||||
|
|
||||||
[SelfHosted(NotSelfHostedOnly = true)]
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
@ -99,7 +106,8 @@ public class UsersController : Controller
|
|||||||
var billingInfo = await _paymentService.GetBillingAsync(user);
|
var billingInfo = await _paymentService.GetBillingAsync(user);
|
||||||
var billingHistoryInfo = await _paymentService.GetBillingHistoryAsync(user);
|
var billingHistoryInfo = await _paymentService.GetBillingHistoryAsync(user);
|
||||||
var isTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(user);
|
var isTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(user);
|
||||||
return View(new UserEditModel(user, isTwoFactorEnabled, ciphers, billingInfo, billingHistoryInfo, _globalSettings));
|
var verifiedDomain = await AccountDeprovisioningEnabled(user.Id);
|
||||||
|
return View(new UserEditModel(user, isTwoFactorEnabled, ciphers, billingInfo, billingHistoryInfo, _globalSettings, verifiedDomain));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -153,4 +161,12 @@ public class UsersController : Controller
|
|||||||
|
|
||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Feature flag to be removed in PM-14207
|
||||||
|
private async Task<bool?> AccountDeprovisioningEnabled(Guid userId)
|
||||||
|
{
|
||||||
|
return _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
||||||
|
? await _userService.IsManagedByAnyOrganizationAsync(userId)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,11 @@ public class UserEditModel
|
|||||||
IEnumerable<Cipher> ciphers,
|
IEnumerable<Cipher> ciphers,
|
||||||
BillingInfo billingInfo,
|
BillingInfo billingInfo,
|
||||||
BillingHistoryInfo billingHistoryInfo,
|
BillingHistoryInfo billingHistoryInfo,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings,
|
||||||
|
bool? domainVerified
|
||||||
|
)
|
||||||
{
|
{
|
||||||
User = UserViewModel.MapViewModel(user, isTwoFactorEnabled, ciphers);
|
User = UserViewModel.MapViewModel(user, isTwoFactorEnabled, ciphers, domainVerified);
|
||||||
|
|
||||||
BillingInfo = billingInfo;
|
BillingInfo = billingInfo;
|
||||||
BillingHistoryInfo = billingHistoryInfo;
|
BillingHistoryInfo = billingHistoryInfo;
|
||||||
|
@ -14,6 +14,7 @@ public class UserViewModel
|
|||||||
public bool Premium { get; }
|
public bool Premium { get; }
|
||||||
public short? MaxStorageGb { get; }
|
public short? MaxStorageGb { get; }
|
||||||
public bool EmailVerified { get; }
|
public bool EmailVerified { get; }
|
||||||
|
public bool? DomainVerified { get; }
|
||||||
public bool TwoFactorEnabled { get; }
|
public bool TwoFactorEnabled { get; }
|
||||||
public DateTime AccountRevisionDate { get; }
|
public DateTime AccountRevisionDate { get; }
|
||||||
public DateTime RevisionDate { get; }
|
public DateTime RevisionDate { get; }
|
||||||
@ -35,6 +36,7 @@ public class UserViewModel
|
|||||||
bool premium,
|
bool premium,
|
||||||
short? maxStorageGb,
|
short? maxStorageGb,
|
||||||
bool emailVerified,
|
bool emailVerified,
|
||||||
|
bool? domainVerified,
|
||||||
bool twoFactorEnabled,
|
bool twoFactorEnabled,
|
||||||
DateTime accountRevisionDate,
|
DateTime accountRevisionDate,
|
||||||
DateTime revisionDate,
|
DateTime revisionDate,
|
||||||
@ -56,6 +58,7 @@ public class UserViewModel
|
|||||||
Premium = premium;
|
Premium = premium;
|
||||||
MaxStorageGb = maxStorageGb;
|
MaxStorageGb = maxStorageGb;
|
||||||
EmailVerified = emailVerified;
|
EmailVerified = emailVerified;
|
||||||
|
DomainVerified = domainVerified;
|
||||||
TwoFactorEnabled = twoFactorEnabled;
|
TwoFactorEnabled = twoFactorEnabled;
|
||||||
AccountRevisionDate = accountRevisionDate;
|
AccountRevisionDate = accountRevisionDate;
|
||||||
RevisionDate = revisionDate;
|
RevisionDate = revisionDate;
|
||||||
@ -73,10 +76,10 @@ public class UserViewModel
|
|||||||
public static IEnumerable<UserViewModel> MapViewModels(
|
public static IEnumerable<UserViewModel> MapViewModels(
|
||||||
IEnumerable<User> users,
|
IEnumerable<User> users,
|
||||||
IEnumerable<(Guid userId, bool twoFactorIsEnabled)> lookup) =>
|
IEnumerable<(Guid userId, bool twoFactorIsEnabled)> lookup) =>
|
||||||
users.Select(user => MapViewModel(user, lookup));
|
users.Select(user => MapViewModel(user, lookup, false));
|
||||||
|
|
||||||
public static UserViewModel MapViewModel(User user,
|
public static UserViewModel MapViewModel(User user,
|
||||||
IEnumerable<(Guid userId, bool twoFactorIsEnabled)> lookup) =>
|
IEnumerable<(Guid userId, bool twoFactorIsEnabled)> lookup, bool? domainVerified) =>
|
||||||
new(
|
new(
|
||||||
user.Id,
|
user.Id,
|
||||||
user.Name,
|
user.Name,
|
||||||
@ -86,6 +89,7 @@ public class UserViewModel
|
|||||||
user.Premium,
|
user.Premium,
|
||||||
user.MaxStorageGb,
|
user.MaxStorageGb,
|
||||||
user.EmailVerified,
|
user.EmailVerified,
|
||||||
|
domainVerified,
|
||||||
IsTwoFactorEnabled(user, lookup),
|
IsTwoFactorEnabled(user, lookup),
|
||||||
user.AccountRevisionDate,
|
user.AccountRevisionDate,
|
||||||
user.RevisionDate,
|
user.RevisionDate,
|
||||||
@ -100,9 +104,9 @@ public class UserViewModel
|
|||||||
Array.Empty<Cipher>());
|
Array.Empty<Cipher>());
|
||||||
|
|
||||||
public static UserViewModel MapViewModel(User user, bool isTwoFactorEnabled) =>
|
public static UserViewModel MapViewModel(User user, bool isTwoFactorEnabled) =>
|
||||||
MapViewModel(user, isTwoFactorEnabled, Array.Empty<Cipher>());
|
MapViewModel(user, isTwoFactorEnabled, Array.Empty<Cipher>(), false);
|
||||||
|
|
||||||
public static UserViewModel MapViewModel(User user, bool isTwoFactorEnabled, IEnumerable<Cipher> ciphers) =>
|
public static UserViewModel MapViewModel(User user, bool isTwoFactorEnabled, IEnumerable<Cipher> ciphers, bool? domainVerified) =>
|
||||||
new(
|
new(
|
||||||
user.Id,
|
user.Id,
|
||||||
user.Name,
|
user.Name,
|
||||||
@ -112,6 +116,7 @@ public class UserViewModel
|
|||||||
user.Premium,
|
user.Premium,
|
||||||
user.MaxStorageGb,
|
user.MaxStorageGb,
|
||||||
user.EmailVerified,
|
user.EmailVerified,
|
||||||
|
domainVerified,
|
||||||
isTwoFactorEnabled,
|
isTwoFactorEnabled,
|
||||||
user.AccountRevisionDate,
|
user.AccountRevisionDate,
|
||||||
user.RevisionDate,
|
user.RevisionDate,
|
||||||
|
@ -110,6 +110,7 @@ public static class RolePermissionMapping
|
|||||||
Permission.User_Licensing_View,
|
Permission.User_Licensing_View,
|
||||||
Permission.User_Billing_View,
|
Permission.User_Billing_View,
|
||||||
Permission.User_Billing_LaunchGateway,
|
Permission.User_Billing_LaunchGateway,
|
||||||
|
Permission.User_Delete,
|
||||||
Permission.Org_List_View,
|
Permission.Org_List_View,
|
||||||
Permission.Org_OrgInformation_View,
|
Permission.Org_OrgInformation_View,
|
||||||
Permission.Org_GeneralDetails_View,
|
Permission.Org_GeneralDetails_View,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
@model UserViewModel
|
@model UserViewModel
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
<dt class="col-sm-4 col-lg-3">Id</dt>
|
<dt class="col-sm-4 col-lg-3">Id</dt>
|
||||||
<dd class="col-sm-8 col-lg-9"><code>@Model.Id</code></dd>
|
<dd class="col-sm-8 col-lg-9"><code>@Model.Id</code></dd>
|
||||||
@ -12,6 +12,11 @@
|
|||||||
<dt class="col-sm-4 col-lg-3">Email Verified</dt>
|
<dt class="col-sm-4 col-lg-3">Email Verified</dt>
|
||||||
<dd class="col-sm-8 col-lg-9">@(Model.EmailVerified ? "Yes" : "No")</dd>
|
<dd class="col-sm-8 col-lg-9">@(Model.EmailVerified ? "Yes" : "No")</dd>
|
||||||
|
|
||||||
|
@if(Model.DomainVerified.HasValue){
|
||||||
|
<dt class="col-sm-4 col-lg-3">Domain Verified</dt>
|
||||||
|
<dd class="col-sm-8 col-lg-9">@(Model.DomainVerified.Value == true ? "Yes" : "No")</dd>
|
||||||
|
}
|
||||||
|
|
||||||
<dt class="col-sm-4 col-lg-3">Using 2FA</dt>
|
<dt class="col-sm-4 col-lg-3">Using 2FA</dt>
|
||||||
<dd class="col-sm-8 col-lg-9">@(Model.TwoFactorEnabled ? "Yes" : "No")</dd>
|
<dd class="col-sm-8 col-lg-9">@(Model.TwoFactorEnabled ? "Yes" : "No")</dd>
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using Bit.Admin.Models;
|
using Bit.Admin.Models;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
|
using Bit.Core.Vault.Entities;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
|
|
||||||
namespace Admin.Test.Models;
|
namespace Admin.Test.Models;
|
||||||
@ -79,7 +80,7 @@ public class UserViewModelTests
|
|||||||
{
|
{
|
||||||
var lookup = new List<(Guid, bool)> { (user.Id, true) };
|
var lookup = new List<(Guid, bool)> { (user.Id, true) };
|
||||||
|
|
||||||
var actual = UserViewModel.MapViewModel(user, lookup);
|
var actual = UserViewModel.MapViewModel(user, lookup, false);
|
||||||
|
|
||||||
Assert.True(actual.TwoFactorEnabled);
|
Assert.True(actual.TwoFactorEnabled);
|
||||||
}
|
}
|
||||||
@ -90,7 +91,7 @@ public class UserViewModelTests
|
|||||||
{
|
{
|
||||||
var lookup = new List<(Guid, bool)> { (user.Id, false) };
|
var lookup = new List<(Guid, bool)> { (user.Id, false) };
|
||||||
|
|
||||||
var actual = UserViewModel.MapViewModel(user, lookup);
|
var actual = UserViewModel.MapViewModel(user, lookup, false);
|
||||||
|
|
||||||
Assert.False(actual.TwoFactorEnabled);
|
Assert.False(actual.TwoFactorEnabled);
|
||||||
}
|
}
|
||||||
@ -101,8 +102,44 @@ public class UserViewModelTests
|
|||||||
{
|
{
|
||||||
var lookup = new List<(Guid, bool)> { (Guid.NewGuid(), true) };
|
var lookup = new List<(Guid, bool)> { (Guid.NewGuid(), true) };
|
||||||
|
|
||||||
var actual = UserViewModel.MapViewModel(user, lookup);
|
var actual = UserViewModel.MapViewModel(user, lookup, false);
|
||||||
|
|
||||||
Assert.False(actual.TwoFactorEnabled);
|
Assert.False(actual.TwoFactorEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public void MapUserViewModel_WithVerifiedDomain_ReturnsUserViewModel(User user)
|
||||||
|
{
|
||||||
|
|
||||||
|
var verifiedDomain = true;
|
||||||
|
|
||||||
|
var actual = UserViewModel.MapViewModel(user, true, Array.Empty<Cipher>(), verifiedDomain);
|
||||||
|
|
||||||
|
Assert.True(actual.DomainVerified);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public void MapUserViewModel_WithoutVerifiedDomain_ReturnsUserViewModel(User user)
|
||||||
|
{
|
||||||
|
|
||||||
|
var verifiedDomain = false;
|
||||||
|
|
||||||
|
var actual = UserViewModel.MapViewModel(user, true, Array.Empty<Cipher>(), verifiedDomain);
|
||||||
|
|
||||||
|
Assert.False(actual.DomainVerified);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public void MapUserViewModel_WithNullVerifiedDomain_ReturnsUserViewModel(User user)
|
||||||
|
{
|
||||||
|
|
||||||
|
var actual = UserViewModel.MapViewModel(user, true, Array.Empty<Cipher>(), null);
|
||||||
|
|
||||||
|
Assert.Null(actual.DomainVerified);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user