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

Log events from the import organization flow (#4632)

* Log events from the import organization flow

* Use an interface for the `OrganizationUser` object used to log events

* Log import events as being from the public api if they are

* Add logging for created groups

* Log proper group ids

* Fix tests

* Also log update events for groups

* Remove private API `import` endpoint

* Make `eventSystemUser` non-nullable for `ImportAsync`

* Fix tests

* Delete `ImportOrganizationUsersRequestModel`

* Fix tests
This commit is contained in:
Addison Beck
2024-08-27 18:19:48 -04:00
committed by GitHub
parent 6764131934
commit acb71d87d9
15 changed files with 85 additions and 143 deletions

View File

@ -1,5 +1,4 @@
using System.Text.Json;
using Bit.Api.AdminConsole.Models.Request;
using Bit.Api.AdminConsole.Models.Request.Organizations;
using Bit.Api.AdminConsole.Models.Response;
using Bit.Api.AdminConsole.Models.Response.Organizations;
@ -312,31 +311,6 @@ public class OrganizationsController : Controller
await _organizationService.DeleteAsync(organization);
}
[HttpPost("{id}/import")]
public async Task Import(string id, [FromBody] ImportOrganizationUsersRequestModel model)
{
if (!_globalSettings.SelfHosted && !model.LargeImport &&
(model.Groups.Count() > 2000 || model.Users.Count(u => !u.Deleted) > 2000))
{
throw new BadRequestException("You cannot import this much data at once.");
}
var orgIdGuid = new Guid(id);
if (!await _currentContext.OrganizationAdmin(orgIdGuid))
{
throw new NotFoundException();
}
var userId = _userService.GetProperUserId(User);
await _organizationService.ImportAsync(
orgIdGuid,
userId.Value,
model.Groups.Select(g => g.ToImportedGroup(orgIdGuid)),
model.Users.Where(u => !u.Deleted).Select(u => u.ToImportedOrganizationUser()),
model.Users.Where(u => u.Deleted).Select(u => u.ExternalId),
model.OverwriteExisting);
}
[HttpPost("{id}/api-key")]
public async Task<ApiKeyResponseModel> ApiKey(string id, [FromBody] OrganizationApiKeyRequestModel model)
{

View File

@ -1,70 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.AdminConsole.Models.Business;
using Bit.Core.Models.Business;
namespace Bit.Api.AdminConsole.Models.Request;
public class ImportOrganizationUsersRequestModel
{
public Group[] Groups { get; set; }
public User[] Users { get; set; }
public bool OverwriteExisting { get; set; }
public bool LargeImport { get; set; }
public class Group
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(300)]
public string ExternalId { get; set; }
public IEnumerable<string> Users { get; set; }
public ImportedGroup ToImportedGroup(Guid organizationId)
{
var importedGroup = new ImportedGroup
{
Group = new Core.AdminConsole.Entities.Group
{
OrganizationId = organizationId,
Name = Name,
ExternalId = ExternalId
},
ExternalUserIds = new HashSet<string>(Users)
};
return importedGroup;
}
}
public class User : IValidatableObject
{
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
public bool Deleted { get; set; }
[Required]
[StringLength(300)]
public string ExternalId { get; set; }
public ImportedOrganizationUser ToImportedOrganizationUser()
{
var importedUser = new ImportedOrganizationUser
{
Email = Email.ToLowerInvariant(),
ExternalId = ExternalId
};
return importedUser;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(Email) && !Deleted)
{
yield return new ValidationResult("Email is required for enabled users.", new string[] { nameof(Email) });
}
}
}
}

View File

@ -3,6 +3,7 @@ using Bit.Api.AdminConsole.Public.Models.Request;
using Bit.Api.AdminConsole.Public.Models.Response;
using Bit.Api.Models.Public.Response;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core.Settings;
@ -49,11 +50,11 @@ public class OrganizationController : Controller
await _organizationService.ImportAsync(
_currentContext.OrganizationId.Value,
null,
model.Groups.Select(g => g.ToImportedGroup(_currentContext.OrganizationId.Value)),
model.Members.Where(u => !u.Deleted).Select(u => u.ToImportedOrganizationUser()),
model.Members.Where(u => u.Deleted).Select(u => u.ExternalId),
model.OverwriteExisting.GetValueOrDefault());
model.OverwriteExisting.GetValueOrDefault(),
EventSystemUser.PublicApi);
return new OkResult();
}
}