mirror of
https://github.com/bitwarden/server.git
synced 2024-11-21 12:05:42 +01:00
[PM-11667] Remove all code related to the outdated custom permissions 'Edit/Delete Assigned Collections' (#4736)
This commit is contained in:
parent
4c0f8d54f3
commit
add8783e31
@ -17,7 +17,6 @@ using Bit.Core.Context;
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.Models.Data;
|
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
|
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
|
||||||
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
@ -108,16 +107,6 @@ public class OrganizationUsersController : Controller
|
|||||||
|
|
||||||
var response = new OrganizationUserDetailsResponseModel(organizationUser.Item1, organizationUser.Item2);
|
var response = new OrganizationUserDetailsResponseModel(organizationUser.Item1, organizationUser.Item2);
|
||||||
|
|
||||||
// Downgrade Custom users with no other permissions than 'Edit/Delete Assigned Collections' to User
|
|
||||||
response.Type = GetFlexibleCollectionsUserType(response.Type, response.Permissions);
|
|
||||||
|
|
||||||
// Set 'Edit/Delete Assigned Collections' custom permissions to false
|
|
||||||
if (response.Permissions is not null)
|
|
||||||
{
|
|
||||||
response.Permissions.EditAssignedCollections = false;
|
|
||||||
response.Permissions.DeleteAssignedCollections = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (includeGroups)
|
if (includeGroups)
|
||||||
{
|
{
|
||||||
response.Groups = await _groupRepository.GetManyIdsByUserIdAsync(organizationUser.Item1.Id);
|
response.Groups = await _groupRepository.GetManyIdsByUserIdAsync(organizationUser.Item1.Id);
|
||||||
@ -638,35 +627,6 @@ public class OrganizationUsersController : Controller
|
|||||||
new OrganizationUserBulkResponseModel(r.Item1.Id, r.Item2)));
|
new OrganizationUserBulkResponseModel(r.Item1.Id, r.Item2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private OrganizationUserType GetFlexibleCollectionsUserType(OrganizationUserType type, Permissions permissions)
|
|
||||||
{
|
|
||||||
// Downgrade Custom users with no other permissions than 'Edit/Delete Assigned Collections' to User
|
|
||||||
if (type == OrganizationUserType.Custom && permissions is not null)
|
|
||||||
{
|
|
||||||
if ((permissions.EditAssignedCollections || permissions.DeleteAssignedCollections) &&
|
|
||||||
permissions is
|
|
||||||
{
|
|
||||||
AccessEventLogs: false,
|
|
||||||
AccessImportExport: false,
|
|
||||||
AccessReports: false,
|
|
||||||
CreateNewCollections: false,
|
|
||||||
EditAnyCollection: false,
|
|
||||||
DeleteAnyCollection: false,
|
|
||||||
ManageGroups: false,
|
|
||||||
ManagePolicies: false,
|
|
||||||
ManageSso: false,
|
|
||||||
ManageUsers: false,
|
|
||||||
ManageResetPassword: false,
|
|
||||||
ManageScim: false
|
|
||||||
})
|
|
||||||
{
|
|
||||||
return OrganizationUserType.User;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<ListResponseModel<OrganizationUserUserDetailsResponseModel>> Get_vNext(Guid orgId,
|
private async Task<ListResponseModel<OrganizationUserUserDetailsResponseModel>> Get_vNext(Guid orgId,
|
||||||
bool includeGroups = false, bool includeCollections = false)
|
bool includeGroups = false, bool includeCollections = false)
|
||||||
{
|
{
|
||||||
|
@ -71,37 +71,6 @@ public class ProfileOrganizationResponseModel : ResponseModel
|
|||||||
KeyConnectorEnabled = ssoConfigData.MemberDecryptionType == MemberDecryptionType.KeyConnector && !string.IsNullOrEmpty(ssoConfigData.KeyConnectorUrl);
|
KeyConnectorEnabled = ssoConfigData.MemberDecryptionType == MemberDecryptionType.KeyConnector && !string.IsNullOrEmpty(ssoConfigData.KeyConnectorUrl);
|
||||||
KeyConnectorUrl = ssoConfigData.KeyConnectorUrl;
|
KeyConnectorUrl = ssoConfigData.KeyConnectorUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Downgrade Custom users with no other permissions than 'Edit/Delete Assigned Collections' to User
|
|
||||||
if (Type == OrganizationUserType.Custom && Permissions is not null)
|
|
||||||
{
|
|
||||||
if ((Permissions.EditAssignedCollections || Permissions.DeleteAssignedCollections) &&
|
|
||||||
Permissions is
|
|
||||||
{
|
|
||||||
AccessEventLogs: false,
|
|
||||||
AccessImportExport: false,
|
|
||||||
AccessReports: false,
|
|
||||||
CreateNewCollections: false,
|
|
||||||
EditAnyCollection: false,
|
|
||||||
DeleteAnyCollection: false,
|
|
||||||
ManageGroups: false,
|
|
||||||
ManagePolicies: false,
|
|
||||||
ManageSso: false,
|
|
||||||
ManageUsers: false,
|
|
||||||
ManageResetPassword: false,
|
|
||||||
ManageScim: false
|
|
||||||
})
|
|
||||||
{
|
|
||||||
organization.Type = OrganizationUserType.User;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set 'Edit/Delete Assigned Collections' custom permissions to false
|
|
||||||
if (Permissions is not null)
|
|
||||||
{
|
|
||||||
Permissions.EditAssignedCollections = false;
|
|
||||||
Permissions.DeleteAssignedCollections = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data;
|
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
|
|
||||||
namespace Bit.Api.AdminConsole.Public.Models;
|
namespace Bit.Api.AdminConsole.Public.Models;
|
||||||
@ -17,7 +16,7 @@ public abstract class MemberBaseModel
|
|||||||
throw new ArgumentNullException(nameof(user));
|
throw new ArgumentNullException(nameof(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
Type = GetFlexibleCollectionsUserType(user.Type, user.GetPermissions());
|
Type = user.Type;
|
||||||
ExternalId = user.ExternalId;
|
ExternalId = user.ExternalId;
|
||||||
ResetPasswordEnrolled = user.ResetPasswordKey != null;
|
ResetPasswordEnrolled = user.ResetPasswordKey != null;
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ public abstract class MemberBaseModel
|
|||||||
throw new ArgumentNullException(nameof(user));
|
throw new ArgumentNullException(nameof(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
Type = GetFlexibleCollectionsUserType(user.Type, user.GetPermissions());
|
Type = user.Type;
|
||||||
ExternalId = user.ExternalId;
|
ExternalId = user.ExternalId;
|
||||||
ResetPasswordEnrolled = user.ResetPasswordKey != null;
|
ResetPasswordEnrolled = user.ResetPasswordKey != null;
|
||||||
|
|
||||||
@ -66,34 +65,4 @@ public abstract class MemberBaseModel
|
|||||||
/// default to false.
|
/// default to false.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PermissionsModel? Permissions { get; set; }
|
public PermissionsModel? Permissions { get; set; }
|
||||||
|
|
||||||
// TODO: AC-2188 - Remove this method when the custom users with no other permissions than 'Edit/Delete Assigned Collections' are migrated
|
|
||||||
private OrganizationUserType GetFlexibleCollectionsUserType(OrganizationUserType type, Permissions permissions)
|
|
||||||
{
|
|
||||||
// Downgrade Custom users with no other permissions than 'Edit/Delete Assigned Collections' to User
|
|
||||||
if (type == OrganizationUserType.Custom)
|
|
||||||
{
|
|
||||||
if ((permissions.EditAssignedCollections || permissions.DeleteAssignedCollections) &&
|
|
||||||
permissions is
|
|
||||||
{
|
|
||||||
AccessEventLogs: false,
|
|
||||||
AccessImportExport: false,
|
|
||||||
AccessReports: false,
|
|
||||||
CreateNewCollections: false,
|
|
||||||
EditAnyCollection: false,
|
|
||||||
DeleteAnyCollection: false,
|
|
||||||
ManageGroups: false,
|
|
||||||
ManagePolicies: false,
|
|
||||||
ManageSso: false,
|
|
||||||
ManageUsers: false,
|
|
||||||
ManageResetPassword: false,
|
|
||||||
ManageScim: false
|
|
||||||
})
|
|
||||||
{
|
|
||||||
return OrganizationUserType.User;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using Bit.Core.Models.Data;
|
namespace Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.Core.Enums;
|
|
||||||
|
|
||||||
public enum OrganizationUserType : byte
|
public enum OrganizationUserType : byte
|
||||||
{
|
{
|
||||||
@ -10,35 +8,3 @@ public enum OrganizationUserType : byte
|
|||||||
// Manager = 3 has been intentionally permanently deleted
|
// Manager = 3 has been intentionally permanently deleted
|
||||||
Custom = 4,
|
Custom = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class OrganizationUserTypeExtensions
|
|
||||||
{
|
|
||||||
public static OrganizationUserType GetFlexibleCollectionsUserType(this OrganizationUserType type, Permissions permissions)
|
|
||||||
{
|
|
||||||
// Downgrade Custom users with no other permissions than 'Edit/Delete Assigned Collections' to User
|
|
||||||
if (type == OrganizationUserType.Custom && permissions is not null)
|
|
||||||
{
|
|
||||||
if ((permissions.EditAssignedCollections || permissions.DeleteAssignedCollections) &&
|
|
||||||
permissions is
|
|
||||||
{
|
|
||||||
AccessEventLogs: false,
|
|
||||||
AccessImportExport: false,
|
|
||||||
AccessReports: false,
|
|
||||||
CreateNewCollections: false,
|
|
||||||
EditAnyCollection: false,
|
|
||||||
DeleteAnyCollection: false,
|
|
||||||
ManageGroups: false,
|
|
||||||
ManagePolicies: false,
|
|
||||||
ManageSso: false,
|
|
||||||
ManageUsers: false,
|
|
||||||
ManageResetPassword: false,
|
|
||||||
ManageScim: false
|
|
||||||
})
|
|
||||||
{
|
|
||||||
return OrganizationUserType.User;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -10,10 +10,6 @@ public class Permissions
|
|||||||
public bool CreateNewCollections { get; set; }
|
public bool CreateNewCollections { get; set; }
|
||||||
public bool EditAnyCollection { get; set; }
|
public bool EditAnyCollection { get; set; }
|
||||||
public bool DeleteAnyCollection { get; set; }
|
public bool DeleteAnyCollection { get; set; }
|
||||||
[Obsolete("Pre-Flexible Collections logic.")]
|
|
||||||
public bool EditAssignedCollections { get; set; }
|
|
||||||
[Obsolete("Pre-Flexible Collections logic.")]
|
|
||||||
public bool DeleteAssignedCollections { get; set; }
|
|
||||||
public bool ManageGroups { get; set; }
|
public bool ManageGroups { get; set; }
|
||||||
public bool ManagePolicies { get; set; }
|
public bool ManagePolicies { get; set; }
|
||||||
public bool ManageSso { get; set; }
|
public bool ManageSso { get; set; }
|
||||||
@ -30,8 +26,6 @@ public class Permissions
|
|||||||
(CreateNewCollections, "createnewcollections"),
|
(CreateNewCollections, "createnewcollections"),
|
||||||
(EditAnyCollection, "editanycollection"),
|
(EditAnyCollection, "editanycollection"),
|
||||||
(DeleteAnyCollection, "deleteanycollection"),
|
(DeleteAnyCollection, "deleteanycollection"),
|
||||||
(EditAssignedCollections, "editassignedcollections"),
|
|
||||||
(DeleteAssignedCollections, "deleteassignedcollections"),
|
|
||||||
(ManageGroups, "managegroups"),
|
(ManageGroups, "managegroups"),
|
||||||
(ManagePolicies, "managepolicies"),
|
(ManagePolicies, "managepolicies"),
|
||||||
(ManageSso, "managesso"),
|
(ManageSso, "managesso"),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
@ -33,15 +32,6 @@ public class OrganizationUserUserDetailsQuery : IOrganizationUserUserDetailsQuer
|
|||||||
{
|
{
|
||||||
var userPermissions = o.GetPermissions();
|
var userPermissions = o.GetPermissions();
|
||||||
|
|
||||||
// Downgrade Custom users with no other permissions than 'Edit/Delete Assigned Collections' to User
|
|
||||||
o.Type = o.Type.GetFlexibleCollectionsUserType(userPermissions);
|
|
||||||
|
|
||||||
if (userPermissions is not null)
|
|
||||||
{
|
|
||||||
userPermissions.EditAssignedCollections = false;
|
|
||||||
userPermissions.DeleteAssignedCollections = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
o.Permissions = CoreHelpers.ClassToJsonData(userPermissions);
|
o.Permissions = CoreHelpers.ClassToJsonData(userPermissions);
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
|
@ -509,8 +509,6 @@ public class CurrentContext : ICurrentContext
|
|||||||
CreateNewCollections = hasClaim("createnewcollections"),
|
CreateNewCollections = hasClaim("createnewcollections"),
|
||||||
EditAnyCollection = hasClaim("editanycollection"),
|
EditAnyCollection = hasClaim("editanycollection"),
|
||||||
DeleteAnyCollection = hasClaim("deleteanycollection"),
|
DeleteAnyCollection = hasClaim("deleteanycollection"),
|
||||||
EditAssignedCollections = hasClaim("editassignedcollections"),
|
|
||||||
DeleteAssignedCollections = hasClaim("deleteassignedcollections"),
|
|
||||||
ManageGroups = hasClaim("managegroups"),
|
ManageGroups = hasClaim("managegroups"),
|
||||||
ManagePolicies = hasClaim("managepolicies"),
|
ManagePolicies = hasClaim("managepolicies"),
|
||||||
ManageSso = hasClaim("managesso"),
|
ManageSso = hasClaim("managesso"),
|
||||||
|
@ -10,7 +10,6 @@ using Bit.Core.Billing.Enums;
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
|
||||||
using Bit.Test.Common.Helpers;
|
using Bit.Test.Common.Helpers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -109,26 +108,6 @@ public class MembersControllerTests : IClassFixture<ApiApplicationFactory>, IAsy
|
|||||||
result.Permissions);
|
result.Permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[BitAutoData(true, true)]
|
|
||||||
[BitAutoData(false, true)]
|
|
||||||
[BitAutoData(true, false)]
|
|
||||||
public async Task Get_CustomMember_WithDeprecatedPermissions_TreatsAsUser(bool editAssignedCollections, bool deleteAssignedCollections)
|
|
||||||
{
|
|
||||||
var (email, orgUser) = await OrganizationTestHelpers.CreateNewUserWithAccountAsync(_factory, _organization.Id,
|
|
||||||
OrganizationUserType.Custom, new Permissions { EditAssignedCollections = editAssignedCollections, DeleteAssignedCollections = deleteAssignedCollections });
|
|
||||||
|
|
||||||
var response = await _client.GetAsync($"/public/members/{orgUser.Id}");
|
|
||||||
|
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
||||||
var result = await response.Content.ReadFromJsonAsync<MemberResponseModel>();
|
|
||||||
Assert.NotNull(result);
|
|
||||||
Assert.Equal(email, result.Email);
|
|
||||||
|
|
||||||
Assert.Equal(OrganizationUserType.User, result.Type);
|
|
||||||
Assert.Null(result.Permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Post_CustomMember_Success()
|
public async Task Post_CustomMember_Success()
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Models.Data;
|
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
||||||
@ -15,33 +12,6 @@ namespace Api.Test.AdminConsole.Queries;
|
|||||||
[SutProviderCustomize]
|
[SutProviderCustomize]
|
||||||
public class OrganizationUserUserDetailsQueryTests
|
public class OrganizationUserUserDetailsQueryTests
|
||||||
{
|
{
|
||||||
[Theory]
|
|
||||||
[BitAutoData]
|
|
||||||
public async Task Get_DowngradesCustomUsersWithDeprecatedPermissions(
|
|
||||||
ICollection<OrganizationUserUserDetails> organizationUsers,
|
|
||||||
SutProvider<OrganizationUserUserDetailsQuery> sutProvider,
|
|
||||||
Guid organizationId)
|
|
||||||
{
|
|
||||||
Get_Setup(organizationUsers, sutProvider, organizationId);
|
|
||||||
|
|
||||||
var customUser = organizationUsers.First();
|
|
||||||
customUser.Type = OrganizationUserType.Custom;
|
|
||||||
customUser.Permissions = CoreHelpers.ClassToJsonData(new Permissions
|
|
||||||
{
|
|
||||||
EditAssignedCollections = true,
|
|
||||||
DeleteAssignedCollections = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
var response = await sutProvider.Sut.GetOrganizationUserUserDetails(new OrganizationUserUserDetailsQueryRequest { OrganizationId = organizationId });
|
|
||||||
|
|
||||||
var customUserResponse = response.First(r => r.Id == organizationUsers.First().Id);
|
|
||||||
Assert.Equal(OrganizationUserType.User, customUserResponse.Type);
|
|
||||||
|
|
||||||
var customUserPermissions = customUserResponse.GetPermissions();
|
|
||||||
Assert.False(customUserPermissions.EditAssignedCollections);
|
|
||||||
Assert.False(customUserPermissions.DeleteAssignedCollections);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
public async Task Get_HandlesNullPermissionsObject(
|
public async Task Get_HandlesNullPermissionsObject(
|
||||||
@ -56,37 +26,6 @@ public class OrganizationUserUserDetailsQueryTests
|
|||||||
Assert.True(response.All(r => organizationUsers.Any(ou => ou.Id == r.Id)));
|
Assert.True(response.All(r => organizationUsers.Any(ou => ou.Id == r.Id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[BitAutoData]
|
|
||||||
public async Task Get_SetsDeprecatedCustomPermissionstoFalse(
|
|
||||||
ICollection<OrganizationUserUserDetails> organizationUsers,
|
|
||||||
SutProvider<OrganizationUserUserDetailsQuery> sutProvider,
|
|
||||||
Guid organizationId)
|
|
||||||
{
|
|
||||||
Get_Setup(organizationUsers, sutProvider, organizationId);
|
|
||||||
|
|
||||||
var customUser = organizationUsers.First();
|
|
||||||
customUser.Type = OrganizationUserType.Custom;
|
|
||||||
customUser.Permissions = CoreHelpers.ClassToJsonData(new Permissions
|
|
||||||
{
|
|
||||||
AccessReports = true,
|
|
||||||
EditAssignedCollections = true,
|
|
||||||
DeleteAssignedCollections = true,
|
|
||||||
AccessEventLogs = true
|
|
||||||
});
|
|
||||||
|
|
||||||
var response = await sutProvider.Sut.GetOrganizationUserUserDetails(new OrganizationUserUserDetailsQueryRequest { OrganizationId = organizationId });
|
|
||||||
|
|
||||||
var customUserResponse = response.First(r => r.Id == organizationUsers.First().Id);
|
|
||||||
Assert.Equal(OrganizationUserType.Custom, customUserResponse.Type);
|
|
||||||
|
|
||||||
var customUserPermissions = customUserResponse.GetPermissions();
|
|
||||||
Assert.True(customUserPermissions.AccessReports);
|
|
||||||
Assert.True(customUserPermissions.AccessEventLogs);
|
|
||||||
Assert.False(customUserPermissions.EditAssignedCollections);
|
|
||||||
Assert.False(customUserPermissions.DeleteAssignedCollections);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
public async Task Get_ReturnsUsers(
|
public async Task Get_ReturnsUsers(
|
||||||
|
@ -15,8 +15,6 @@ public class PermissionsTests
|
|||||||
"\"createNewCollections\": true,",
|
"\"createNewCollections\": true,",
|
||||||
"\"editAnyCollection\": true,",
|
"\"editAnyCollection\": true,",
|
||||||
"\"deleteAnyCollection\": true,",
|
"\"deleteAnyCollection\": true,",
|
||||||
"\"editAssignedCollections\": false,",
|
|
||||||
"\"deleteAssignedCollections\": false,",
|
|
||||||
"\"manageGroups\": false,",
|
"\"manageGroups\": false,",
|
||||||
"\"managePolicies\": false,",
|
"\"managePolicies\": false,",
|
||||||
"\"manageSso\": false,",
|
"\"manageSso\": false,",
|
||||||
@ -36,8 +34,6 @@ public class PermissionsTests
|
|||||||
CreateNewCollections = true,
|
CreateNewCollections = true,
|
||||||
EditAnyCollection = true,
|
EditAnyCollection = true,
|
||||||
DeleteAnyCollection = true,
|
DeleteAnyCollection = true,
|
||||||
EditAssignedCollections = false,
|
|
||||||
DeleteAssignedCollections = false,
|
|
||||||
ManageGroups = false,
|
ManageGroups = false,
|
||||||
ManagePolicies = false,
|
ManagePolicies = false,
|
||||||
ManageSso = false,
|
ManageSso = false,
|
||||||
|
@ -1,335 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
using Bit.Core.AdminConsole.Entities;
|
|
||||||
using Bit.Core.Entities;
|
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Bit.Core.Models.Data;
|
|
||||||
using Bit.Core.Repositories;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Bit.Infrastructure.IntegrationTest.Services;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Bit.Infrastructure.IntegrationTest.AdminConsole.Migrations;
|
|
||||||
|
|
||||||
public class FinalFlexibleCollectionsDataMigrationsTests
|
|
||||||
{
|
|
||||||
private const string _migrationName = "FinalFlexibleCollectionsDataMigrations";
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData(MigrationName = _migrationName)]
|
|
||||||
public async Task RunMigration_WithEditAssignedCollections_WithCustomUserType_MigratesToUserNullPermissions(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
IMigrationTesterService migrationTester)
|
|
||||||
{
|
|
||||||
// Setup data
|
|
||||||
var orgUser = await SetupData(
|
|
||||||
userRepository, organizationRepository, organizationUserRepository,
|
|
||||||
OrganizationUserType.Custom, editAssignedCollections: true, deleteAssignedCollections: false);
|
|
||||||
|
|
||||||
// Run data migration
|
|
||||||
migrationTester.ApplyMigration();
|
|
||||||
|
|
||||||
// Assert that the user was migrated to a User type with null permissions
|
|
||||||
var migratedOrgUser = await organizationUserRepository.GetByIdAsync(orgUser.Id);
|
|
||||||
Assert.NotNull(migratedOrgUser);
|
|
||||||
Assert.Equal(orgUser.Id, migratedOrgUser.Id);
|
|
||||||
Assert.Equal(OrganizationUserType.User, migratedOrgUser.Type);
|
|
||||||
Assert.Null(migratedOrgUser.Permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData(MigrationName = _migrationName)]
|
|
||||||
public async Task RunMigration_WithDeleteAssignedCollections_WithCustomUserType_MigratesToUserNullPermissions(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
IMigrationTesterService migrationTester)
|
|
||||||
{
|
|
||||||
// Setup data
|
|
||||||
var orgUser = await SetupData(
|
|
||||||
userRepository, organizationRepository, organizationUserRepository,
|
|
||||||
OrganizationUserType.Custom, editAssignedCollections: false, deleteAssignedCollections: true);
|
|
||||||
|
|
||||||
// Run data migration
|
|
||||||
migrationTester.ApplyMigration();
|
|
||||||
|
|
||||||
// Assert that the user was migrated to a User type with null permissions
|
|
||||||
var migratedOrgUser = await organizationUserRepository.GetByIdAsync(orgUser.Id);
|
|
||||||
Assert.NotNull(migratedOrgUser);
|
|
||||||
Assert.Equal(orgUser.Id, migratedOrgUser.Id);
|
|
||||||
Assert.Equal(OrganizationUserType.User, migratedOrgUser.Type);
|
|
||||||
Assert.Null(migratedOrgUser.Permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData(MigrationName = _migrationName)]
|
|
||||||
public async Task RunMigration_WithEditAndDeleteAssignedCollections_WithCustomUserType_MigratesToUserNullPermissions(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
IMigrationTesterService migrationTester)
|
|
||||||
{
|
|
||||||
// Setup data
|
|
||||||
var orgUser = await SetupData(
|
|
||||||
userRepository, organizationRepository, organizationUserRepository,
|
|
||||||
OrganizationUserType.Custom, editAssignedCollections: true, deleteAssignedCollections: true);
|
|
||||||
|
|
||||||
// Run data migration
|
|
||||||
migrationTester.ApplyMigration();
|
|
||||||
|
|
||||||
// Assert that the user was migrated to a User type with null permissions
|
|
||||||
var migratedOrgUser = await organizationUserRepository.GetByIdAsync(orgUser.Id);
|
|
||||||
Assert.NotNull(migratedOrgUser);
|
|
||||||
Assert.Equal(orgUser.Id, migratedOrgUser.Id);
|
|
||||||
Assert.Equal(OrganizationUserType.User, migratedOrgUser.Type);
|
|
||||||
Assert.Null(migratedOrgUser.Permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData(MigrationName = _migrationName)]
|
|
||||||
public async Task RunMigration_WithoutAssignedCollectionsPermissions_WithCustomUserType_RemovesAssignedCollectionsPermissions(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
IMigrationTesterService migrationTester)
|
|
||||||
{
|
|
||||||
// Setup data
|
|
||||||
var orgUser = await SetupData(
|
|
||||||
userRepository, organizationRepository, organizationUserRepository, OrganizationUserType.Custom,
|
|
||||||
editAssignedCollections: false, deleteAssignedCollections: false, accessEventLogs: true);
|
|
||||||
|
|
||||||
// Run data migration
|
|
||||||
migrationTester.ApplyMigration();
|
|
||||||
|
|
||||||
// Assert that the user kept the accessEventLogs permission and lost the editAssignedCollections and deleteAssignedCollections permissions
|
|
||||||
var migratedOrgUser = await organizationUserRepository.GetByIdAsync(orgUser.Id);
|
|
||||||
Assert.NotNull(migratedOrgUser);
|
|
||||||
Assert.Equal(orgUser.Id, migratedOrgUser.Id);
|
|
||||||
Assert.Equal(OrganizationUserType.Custom, migratedOrgUser.Type);
|
|
||||||
Assert.NotEqual(orgUser.Permissions, migratedOrgUser.Permissions);
|
|
||||||
Assert.NotNull(migratedOrgUser.Permissions);
|
|
||||||
Assert.Contains("accessEventLogs", orgUser.Permissions);
|
|
||||||
Assert.Contains("editAssignedCollections", orgUser.Permissions);
|
|
||||||
Assert.Contains("deleteAssignedCollections", orgUser.Permissions);
|
|
||||||
|
|
||||||
Assert.Contains("accessEventLogs", migratedOrgUser.Permissions);
|
|
||||||
var migratedOrgUserPermissions = migratedOrgUser.GetPermissions();
|
|
||||||
Assert.NotNull(migratedOrgUserPermissions);
|
|
||||||
Assert.True(migratedOrgUserPermissions.AccessEventLogs);
|
|
||||||
Assert.DoesNotContain("editAssignedCollections", migratedOrgUser.Permissions);
|
|
||||||
Assert.DoesNotContain("deleteAssignedCollections", migratedOrgUser.Permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData(MigrationName = _migrationName)]
|
|
||||||
public async Task RunMigration_WithAdminUserType_RemovesAssignedCollectionsPermissions(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
IMigrationTesterService migrationTester)
|
|
||||||
{
|
|
||||||
// Setup data
|
|
||||||
var orgUser = await SetupData(
|
|
||||||
userRepository, organizationRepository, organizationUserRepository, OrganizationUserType.Admin,
|
|
||||||
editAssignedCollections: false, deleteAssignedCollections: false, accessEventLogs: true);
|
|
||||||
|
|
||||||
// Run data migration
|
|
||||||
migrationTester.ApplyMigration();
|
|
||||||
|
|
||||||
// Assert that the user kept the Admin type and lost the editAssignedCollections and deleteAssignedCollections
|
|
||||||
// permissions but kept the accessEventLogs permission
|
|
||||||
var migratedOrgUser = await organizationUserRepository.GetByIdAsync(orgUser.Id);
|
|
||||||
Assert.NotNull(migratedOrgUser);
|
|
||||||
Assert.Equal(orgUser.Id, migratedOrgUser.Id);
|
|
||||||
Assert.Equal(OrganizationUserType.Admin, migratedOrgUser.Type);
|
|
||||||
Assert.NotEqual(orgUser.Permissions, migratedOrgUser.Permissions);
|
|
||||||
Assert.NotNull(migratedOrgUser.Permissions);
|
|
||||||
Assert.Contains("accessEventLogs", orgUser.Permissions);
|
|
||||||
Assert.Contains("editAssignedCollections", orgUser.Permissions);
|
|
||||||
Assert.Contains("deleteAssignedCollections", orgUser.Permissions);
|
|
||||||
|
|
||||||
Assert.Contains("accessEventLogs", migratedOrgUser.Permissions);
|
|
||||||
Assert.True(migratedOrgUser.GetPermissions().AccessEventLogs);
|
|
||||||
Assert.DoesNotContain("editAssignedCollections", migratedOrgUser.Permissions);
|
|
||||||
Assert.DoesNotContain("deleteAssignedCollections", migratedOrgUser.Permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData(MigrationName = _migrationName)]
|
|
||||||
public async Task RunMigration_WithoutAssignedCollectionsPermissions_DoesNothing(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
IMigrationTesterService migrationTester)
|
|
||||||
{
|
|
||||||
// Setup data
|
|
||||||
var orgUser = await SetupData(
|
|
||||||
userRepository, organizationRepository, organizationUserRepository, OrganizationUserType.Custom,
|
|
||||||
editAssignedCollections: false, deleteAssignedCollections: false, accessEventLogs: false);
|
|
||||||
// Remove the editAssignedCollections and deleteAssignedCollections permissions
|
|
||||||
orgUser.Permissions = JsonSerializer.Serialize(new
|
|
||||||
{
|
|
||||||
AccessEventLogs = false,
|
|
||||||
AccessImportExport = false,
|
|
||||||
AccessReports = false,
|
|
||||||
CreateNewCollections = false,
|
|
||||||
EditAnyCollection = false,
|
|
||||||
DeleteAnyCollection = false,
|
|
||||||
ManageGroups = false,
|
|
||||||
ManagePolicies = false,
|
|
||||||
ManageSso = false,
|
|
||||||
ManageUsers = false,
|
|
||||||
ManageResetPassword = false,
|
|
||||||
ManageScim = false
|
|
||||||
}, JsonHelpers.CamelCase);
|
|
||||||
await organizationUserRepository.ReplaceAsync(orgUser);
|
|
||||||
|
|
||||||
// Run data migration
|
|
||||||
migrationTester.ApplyMigration();
|
|
||||||
|
|
||||||
// Assert that the user remained unchanged
|
|
||||||
var migratedOrgUser = await organizationUserRepository.GetByIdAsync(orgUser.Id);
|
|
||||||
Assert.NotNull(migratedOrgUser);
|
|
||||||
Assert.Equal(orgUser.Id, migratedOrgUser.Id);
|
|
||||||
Assert.Equal(OrganizationUserType.Custom, orgUser.Type);
|
|
||||||
Assert.Equal(OrganizationUserType.Custom, migratedOrgUser.Type);
|
|
||||||
Assert.NotNull(migratedOrgUser.Permissions);
|
|
||||||
// Assert that the permissions remain unchanged by comparing JSON data, ignoring the order of properties
|
|
||||||
Assert.True(JToken.DeepEquals(JObject.Parse(orgUser.Permissions), JObject.Parse(migratedOrgUser.Permissions)));
|
|
||||||
}
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData(MigrationName = _migrationName)]
|
|
||||||
public async Task RunMigration_HandlesNull(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
IMigrationTesterService migrationTester)
|
|
||||||
{
|
|
||||||
// Setup data
|
|
||||||
var orgUser = await SetupData(
|
|
||||||
userRepository, organizationRepository, organizationUserRepository, OrganizationUserType.Custom,
|
|
||||||
editAssignedCollections: false, deleteAssignedCollections: false, accessEventLogs: false);
|
|
||||||
|
|
||||||
orgUser.Permissions = null;
|
|
||||||
await organizationUserRepository.ReplaceAsync(orgUser);
|
|
||||||
|
|
||||||
// Run data migration
|
|
||||||
migrationTester.ApplyMigration();
|
|
||||||
|
|
||||||
// Assert no changes
|
|
||||||
var migratedOrgUser = await organizationUserRepository.GetByIdAsync(orgUser.Id);
|
|
||||||
Assert.NotNull(migratedOrgUser);
|
|
||||||
Assert.Equal(orgUser.Id, migratedOrgUser.Id);
|
|
||||||
Assert.Equal(orgUser.Type, migratedOrgUser.Type);
|
|
||||||
Assert.Null(migratedOrgUser.Permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData(MigrationName = _migrationName)]
|
|
||||||
public async Task RunMigration_HandlesNullString(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
IMigrationTesterService migrationTester)
|
|
||||||
{
|
|
||||||
// Setup data
|
|
||||||
var orgUser = await SetupData(
|
|
||||||
userRepository, organizationRepository, organizationUserRepository, OrganizationUserType.Custom,
|
|
||||||
editAssignedCollections: false, deleteAssignedCollections: false, accessEventLogs: false);
|
|
||||||
|
|
||||||
// We haven't tracked down the source of this yet but it does occur in our cloud database
|
|
||||||
orgUser.Permissions = "NULL";
|
|
||||||
await organizationUserRepository.ReplaceAsync(orgUser);
|
|
||||||
|
|
||||||
// Run data migration
|
|
||||||
migrationTester.ApplyMigration();
|
|
||||||
|
|
||||||
// Assert no changes
|
|
||||||
var migratedOrgUser = await organizationUserRepository.GetByIdAsync(orgUser.Id);
|
|
||||||
Assert.NotNull(migratedOrgUser);
|
|
||||||
Assert.Equal(orgUser.Id, migratedOrgUser.Id);
|
|
||||||
Assert.Equal(orgUser.Type, migratedOrgUser.Type);
|
|
||||||
Assert.Equal("NULL", migratedOrgUser.Permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData(MigrationName = _migrationName)]
|
|
||||||
public async Task RunMigration_HandlesNonJsonValues(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
IMigrationTesterService migrationTester)
|
|
||||||
{
|
|
||||||
// Setup data
|
|
||||||
var orgUser = await SetupData(
|
|
||||||
userRepository, organizationRepository, organizationUserRepository, OrganizationUserType.Custom,
|
|
||||||
editAssignedCollections: false, deleteAssignedCollections: false, accessEventLogs: false);
|
|
||||||
|
|
||||||
orgUser.Permissions = "asdfasdfasfd";
|
|
||||||
await organizationUserRepository.ReplaceAsync(orgUser);
|
|
||||||
|
|
||||||
// Run data migration
|
|
||||||
migrationTester.ApplyMigration();
|
|
||||||
|
|
||||||
// Assert no changes
|
|
||||||
var migratedOrgUser = await organizationUserRepository.GetByIdAsync(orgUser.Id);
|
|
||||||
Assert.NotNull(migratedOrgUser);
|
|
||||||
Assert.Equal(orgUser.Id, migratedOrgUser.Id);
|
|
||||||
Assert.Equal(orgUser.Type, migratedOrgUser.Type);
|
|
||||||
Assert.Equal("asdfasdfasfd", migratedOrgUser.Permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<OrganizationUser> SetupData(
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
|
||||||
OrganizationUserType organizationUserType,
|
|
||||||
bool editAssignedCollections,
|
|
||||||
bool deleteAssignedCollections,
|
|
||||||
bool accessEventLogs = false)
|
|
||||||
{
|
|
||||||
var permissions = new Permissions
|
|
||||||
{
|
|
||||||
AccessEventLogs = accessEventLogs,
|
|
||||||
AccessImportExport = false,
|
|
||||||
AccessReports = false,
|
|
||||||
CreateNewCollections = false,
|
|
||||||
EditAnyCollection = false,
|
|
||||||
DeleteAnyCollection = false,
|
|
||||||
EditAssignedCollections = editAssignedCollections,
|
|
||||||
DeleteAssignedCollections = deleteAssignedCollections,
|
|
||||||
ManageGroups = false,
|
|
||||||
ManagePolicies = false,
|
|
||||||
ManageSso = false,
|
|
||||||
ManageUsers = false,
|
|
||||||
ManageResetPassword = false,
|
|
||||||
ManageScim = false
|
|
||||||
};
|
|
||||||
|
|
||||||
var user = await userRepository.CreateAsync(new User
|
|
||||||
{
|
|
||||||
Name = "Test User 1",
|
|
||||||
Email = $"test+{Guid.NewGuid()}@example.com",
|
|
||||||
ApiKey = "TEST",
|
|
||||||
SecurityStamp = "stamp",
|
|
||||||
Kdf = KdfType.PBKDF2_SHA256,
|
|
||||||
KdfIterations = 1,
|
|
||||||
KdfMemory = 2,
|
|
||||||
KdfParallelism = 3
|
|
||||||
});
|
|
||||||
|
|
||||||
var organization = await organizationRepository.CreateAsync(new Organization
|
|
||||||
{
|
|
||||||
Name = "Test Org",
|
|
||||||
BillingEmail = user.Email, // TODO: EF does not enforce this being NOT NULl
|
|
||||||
Plan = "Test", // TODO: EF does not enforce this being NOT NULl
|
|
||||||
PrivateKey = "privatekey",
|
|
||||||
});
|
|
||||||
|
|
||||||
var orgUser = await organizationUserRepository.CreateAsync(new OrganizationUser
|
|
||||||
{
|
|
||||||
OrganizationId = organization.Id,
|
|
||||||
UserId = user.Id,
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
ResetPasswordKey = "resetpasswordkey1",
|
|
||||||
Type = organizationUserType,
|
|
||||||
Permissions = JsonSerializer.Serialize(permissions, JsonHelpers.CamelCase)
|
|
||||||
});
|
|
||||||
|
|
||||||
return orgUser;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user