mirror of
https://github.com/bitwarden/server.git
synced 2025-07-01 08:02:49 -05:00
[AC-1200] Admin Console code ownership - move OrganizationFeatures (#3369)
This commit is contained in:
@ -0,0 +1,32 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys;
|
||||
|
||||
public class CreateOrganizationApiKeyCommand : ICreateOrganizationApiKeyCommand
|
||||
{
|
||||
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
|
||||
|
||||
public CreateOrganizationApiKeyCommand(IOrganizationApiKeyRepository organizationApiKeyRepository)
|
||||
{
|
||||
_organizationApiKeyRepository = organizationApiKeyRepository;
|
||||
}
|
||||
|
||||
public async Task<OrganizationApiKey> CreateAsync(Guid organizationId,
|
||||
OrganizationApiKeyType organizationApiKeyType)
|
||||
{
|
||||
var apiKey = new OrganizationApiKey
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Type = organizationApiKeyType,
|
||||
ApiKey = CoreHelpers.SecureRandomString(30),
|
||||
RevisionDate = DateTime.UtcNow,
|
||||
};
|
||||
|
||||
await _organizationApiKeyRepository.CreateAsync(apiKey);
|
||||
return apiKey;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys;
|
||||
|
||||
public class GetOrganizationApiKeyQuery : IGetOrganizationApiKeyQuery
|
||||
{
|
||||
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
|
||||
|
||||
public GetOrganizationApiKeyQuery(IOrganizationApiKeyRepository organizationApiKeyRepository)
|
||||
{
|
||||
_organizationApiKeyRepository = organizationApiKeyRepository;
|
||||
}
|
||||
|
||||
public async Task<OrganizationApiKey> GetOrganizationApiKeyAsync(Guid organizationId, OrganizationApiKeyType organizationApiKeyType)
|
||||
{
|
||||
if (!Enum.IsDefined(organizationApiKeyType))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(organizationApiKeyType), $"Invalid value for enum {nameof(OrganizationApiKeyType)}");
|
||||
}
|
||||
|
||||
var apiKeys = await _organizationApiKeyRepository
|
||||
.GetManyByOrganizationIdTypeAsync(organizationId, organizationApiKeyType);
|
||||
|
||||
// NOTE: Currently we only allow one type of api key per organization
|
||||
return apiKeys.SingleOrDefault();
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
|
||||
|
||||
public interface ICreateOrganizationApiKeyCommand
|
||||
{
|
||||
Task<OrganizationApiKey> CreateAsync(Guid organizationId, OrganizationApiKeyType organizationApiKeyType);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
|
||||
|
||||
public interface IGetOrganizationApiKeyQuery
|
||||
{
|
||||
Task<OrganizationApiKey> GetOrganizationApiKeyAsync(Guid organizationId, OrganizationApiKeyType organizationApiKeyType);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
|
||||
|
||||
public interface IRotateOrganizationApiKeyCommand
|
||||
{
|
||||
Task<OrganizationApiKey> RotateApiKeyAsync(OrganizationApiKey organizationApiKey);
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys;
|
||||
|
||||
public class RotateOrganizationApiKeyCommand : IRotateOrganizationApiKeyCommand
|
||||
{
|
||||
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
|
||||
|
||||
public RotateOrganizationApiKeyCommand(IOrganizationApiKeyRepository organizationApiKeyRepository)
|
||||
{
|
||||
_organizationApiKeyRepository = organizationApiKeyRepository;
|
||||
}
|
||||
|
||||
public async Task<OrganizationApiKey> RotateApiKeyAsync(OrganizationApiKey organizationApiKey)
|
||||
{
|
||||
organizationApiKey.ApiKey = CoreHelpers.SecureRandomString(30);
|
||||
organizationApiKey.RevisionDate = DateTime.UtcNow;
|
||||
await _organizationApiKeyRepository.UpsertAsync(organizationApiKey);
|
||||
return organizationApiKey;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationConnections;
|
||||
using Bit.Core.Models.OrganizationConnectionConfigs;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections;
|
||||
|
||||
public class CreateOrganizationConnectionCommand : ICreateOrganizationConnectionCommand
|
||||
{
|
||||
private readonly IOrganizationConnectionRepository _organizationConnectionRepository;
|
||||
|
||||
public CreateOrganizationConnectionCommand(IOrganizationConnectionRepository organizationConnectionRepository)
|
||||
{
|
||||
_organizationConnectionRepository = organizationConnectionRepository;
|
||||
}
|
||||
|
||||
public async Task<OrganizationConnection> CreateAsync<T>(OrganizationConnectionData<T> connectionData) where T : IConnectionConfig
|
||||
{
|
||||
return await _organizationConnectionRepository.CreateAsync(connectionData.ToEntity());
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections;
|
||||
|
||||
public class DeleteOrganizationConnectionCommand : IDeleteOrganizationConnectionCommand
|
||||
{
|
||||
private readonly IOrganizationConnectionRepository _organizationConnectionRepository;
|
||||
|
||||
public DeleteOrganizationConnectionCommand(IOrganizationConnectionRepository organizationConnectionRepository)
|
||||
{
|
||||
_organizationConnectionRepository = organizationConnectionRepository;
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(OrganizationConnection connection)
|
||||
{
|
||||
await _organizationConnectionRepository.DeleteAsync(connection);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationConnections;
|
||||
using Bit.Core.Models.OrganizationConnectionConfigs;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections.Interfaces;
|
||||
|
||||
public interface ICreateOrganizationConnectionCommand
|
||||
{
|
||||
Task<OrganizationConnection> CreateAsync<T>(OrganizationConnectionData<T> connectionData) where T : IConnectionConfig;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections.Interfaces;
|
||||
|
||||
public interface IDeleteOrganizationConnectionCommand
|
||||
{
|
||||
Task DeleteAsync(OrganizationConnection connection);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationConnections;
|
||||
using Bit.Core.Models.OrganizationConnectionConfigs;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections.Interfaces;
|
||||
|
||||
public interface IUpdateOrganizationConnectionCommand
|
||||
{
|
||||
Task<OrganizationConnection> UpdateAsync<T>(OrganizationConnectionData<T> connectionData) where T : IConnectionConfig;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections.Interfaces;
|
||||
|
||||
public interface IValidateBillingSyncKeyCommand
|
||||
{
|
||||
Task<bool> ValidateBillingSyncKeyAsync(Organization organization, string billingSyncKey);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationConnections;
|
||||
using Bit.Core.Models.OrganizationConnectionConfigs;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections;
|
||||
|
||||
public class UpdateOrganizationConnectionCommand : IUpdateOrganizationConnectionCommand
|
||||
{
|
||||
private readonly IOrganizationConnectionRepository _organizationConnectionRepository;
|
||||
|
||||
public UpdateOrganizationConnectionCommand(IOrganizationConnectionRepository organizationConnectionRepository)
|
||||
{
|
||||
_organizationConnectionRepository = organizationConnectionRepository;
|
||||
}
|
||||
|
||||
public async Task<OrganizationConnection> UpdateAsync<T>(OrganizationConnectionData<T> connectionData) where T : IConnectionConfig
|
||||
{
|
||||
if (!connectionData.Id.HasValue)
|
||||
{
|
||||
throw new Exception("Cannot update connection, Connection does not exist.");
|
||||
}
|
||||
|
||||
var connection = await _organizationConnectionRepository.GetByIdAsync(connectionData.Id.Value);
|
||||
|
||||
if (connection == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var entity = connectionData.ToEntity();
|
||||
await _organizationConnectionRepository.UpsertAsync(entity);
|
||||
return entity;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationConnections;
|
||||
|
||||
public class ValidateBillingSyncKeyCommand : IValidateBillingSyncKeyCommand
|
||||
{
|
||||
private readonly IOrganizationApiKeyRepository _apiKeyRepository;
|
||||
|
||||
public ValidateBillingSyncKeyCommand(
|
||||
IOrganizationApiKeyRepository organizationApiKeyRepository)
|
||||
{
|
||||
_apiKeyRepository = organizationApiKeyRepository;
|
||||
}
|
||||
|
||||
public async Task<bool> ValidateBillingSyncKeyAsync(Organization organization, string billingSyncKey)
|
||||
{
|
||||
if (organization == null)
|
||||
{
|
||||
throw new BadRequestException("Invalid organization");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(billingSyncKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var orgApiKey = (await _apiKeyRepository.GetManyByOrganizationIdTypeAsync(organization.Id, Core.Enums.OrganizationApiKeyType.BillingSync)).FirstOrDefault();
|
||||
if (string.Equals(orgApiKey.ApiKey, billingSyncKey))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
|
||||
public class CreateOrganizationDomainCommand : ICreateOrganizationDomainCommand
|
||||
{
|
||||
private readonly IOrganizationDomainRepository _organizationDomainRepository;
|
||||
private readonly IEventService _eventService;
|
||||
private readonly IDnsResolverService _dnsResolverService;
|
||||
private readonly ILogger<VerifyOrganizationDomainCommand> _logger;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public CreateOrganizationDomainCommand(
|
||||
IOrganizationDomainRepository organizationDomainRepository,
|
||||
IEventService eventService,
|
||||
IDnsResolverService dnsResolverService,
|
||||
ILogger<VerifyOrganizationDomainCommand> logger,
|
||||
IGlobalSettings globalSettings)
|
||||
{
|
||||
_organizationDomainRepository = organizationDomainRepository;
|
||||
_eventService = eventService;
|
||||
_dnsResolverService = dnsResolverService;
|
||||
_logger = logger;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
public async Task<OrganizationDomain> CreateAsync(OrganizationDomain organizationDomain)
|
||||
{
|
||||
//Domains claimed and verified by an organization cannot be claimed
|
||||
var claimedDomain =
|
||||
await _organizationDomainRepository.GetClaimedDomainsByDomainNameAsync(organizationDomain.DomainName);
|
||||
if (claimedDomain.Any())
|
||||
{
|
||||
throw new ConflictException("The domain is not available to be claimed.");
|
||||
}
|
||||
|
||||
//check for duplicate domain entry for an organization
|
||||
var duplicateOrgDomain =
|
||||
await _organizationDomainRepository.GetDomainByOrgIdAndDomainNameAsync(organizationDomain.OrganizationId,
|
||||
organizationDomain.DomainName);
|
||||
if (duplicateOrgDomain is not null)
|
||||
{
|
||||
throw new ConflictException("A domain already exists for this organization.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (await _dnsResolverService.ResolveAsync(organizationDomain.DomainName, organizationDomain.Txt))
|
||||
{
|
||||
organizationDomain.SetVerifiedDate();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("Error verifying Organization domain.", e);
|
||||
}
|
||||
|
||||
organizationDomain.SetNextRunDate(_globalSettings.DomainVerification.VerificationInterval);
|
||||
organizationDomain.SetLastCheckedDate();
|
||||
|
||||
var orgDomain = await _organizationDomainRepository.CreateAsync(organizationDomain);
|
||||
|
||||
await _eventService.LogOrganizationDomainEventAsync(orgDomain, EventType.OrganizationDomain_Added);
|
||||
await _eventService.LogOrganizationDomainEventAsync(orgDomain,
|
||||
orgDomain.VerifiedDate != null ? EventType.OrganizationDomain_Verified : EventType.OrganizationDomain_NotVerified);
|
||||
|
||||
return orgDomain;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
|
||||
public class DeleteOrganizationDomainCommand : IDeleteOrganizationDomainCommand
|
||||
{
|
||||
private readonly IOrganizationDomainRepository _organizationDomainRepository;
|
||||
private readonly IEventService _eventService;
|
||||
|
||||
public DeleteOrganizationDomainCommand(IOrganizationDomainRepository organizationDomainRepository,
|
||||
IEventService eventService)
|
||||
{
|
||||
_organizationDomainRepository = organizationDomainRepository;
|
||||
_eventService = eventService;
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(OrganizationDomain organizationDomain)
|
||||
{
|
||||
await _organizationDomainRepository.DeleteAsync(organizationDomain);
|
||||
await _eventService.LogOrganizationDomainEventAsync(organizationDomain, EventType.OrganizationDomain_Removed);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
|
||||
public class GetOrganizationDomainByIdOrganizationIdQuery : IGetOrganizationDomainByIdOrganizationIdQuery
|
||||
{
|
||||
private readonly IOrganizationDomainRepository _organizationDomainRepository;
|
||||
|
||||
public GetOrganizationDomainByIdOrganizationIdQuery(IOrganizationDomainRepository organizationDomainRepository)
|
||||
{
|
||||
_organizationDomainRepository = organizationDomainRepository;
|
||||
}
|
||||
|
||||
public async Task<OrganizationDomain> GetOrganizationDomainByIdOrganizationIdAsync(Guid id, Guid organizationId)
|
||||
=> await _organizationDomainRepository.GetDomainByIdOrganizationIdAsync(id, organizationId);
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
|
||||
public class GetOrganizationDomainByOrganizationIdQuery : IGetOrganizationDomainByOrganizationIdQuery
|
||||
{
|
||||
private readonly IOrganizationDomainRepository _organizationDomainRepository;
|
||||
|
||||
public GetOrganizationDomainByOrganizationIdQuery(IOrganizationDomainRepository organizationDomainRepository)
|
||||
{
|
||||
_organizationDomainRepository = organizationDomainRepository;
|
||||
}
|
||||
|
||||
public async Task<ICollection<OrganizationDomain>> GetDomainsByOrganizationIdAsync(Guid orgId)
|
||||
=> await _organizationDomainRepository.GetDomainsByOrganizationIdAsync(orgId);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
|
||||
public interface ICreateOrganizationDomainCommand
|
||||
{
|
||||
Task<OrganizationDomain> CreateAsync(OrganizationDomain organizationDomain);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
|
||||
public interface IDeleteOrganizationDomainCommand
|
||||
{
|
||||
Task DeleteAsync(OrganizationDomain organizationDomain);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
|
||||
public interface IGetOrganizationDomainByIdOrganizationIdQuery
|
||||
{
|
||||
Task<OrganizationDomain> GetOrganizationDomainByIdOrganizationIdAsync(Guid id, Guid organizationId);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
|
||||
public interface IGetOrganizationDomainByOrganizationIdQuery
|
||||
{
|
||||
Task<ICollection<OrganizationDomain>> GetDomainsByOrganizationIdAsync(Guid orgId);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
|
||||
public interface IVerifyOrganizationDomainCommand
|
||||
{
|
||||
Task<OrganizationDomain> VerifyOrganizationDomainAsync(OrganizationDomain organizationDomain);
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
|
||||
public class VerifyOrganizationDomainCommand : IVerifyOrganizationDomainCommand
|
||||
{
|
||||
private readonly IOrganizationDomainRepository _organizationDomainRepository;
|
||||
private readonly IDnsResolverService _dnsResolverService;
|
||||
private readonly IEventService _eventService;
|
||||
private readonly ILogger<VerifyOrganizationDomainCommand> _logger;
|
||||
|
||||
public VerifyOrganizationDomainCommand(
|
||||
IOrganizationDomainRepository organizationDomainRepository,
|
||||
IDnsResolverService dnsResolverService,
|
||||
IEventService eventService,
|
||||
ILogger<VerifyOrganizationDomainCommand> logger)
|
||||
{
|
||||
_organizationDomainRepository = organizationDomainRepository;
|
||||
_dnsResolverService = dnsResolverService;
|
||||
_eventService = eventService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<OrganizationDomain> VerifyOrganizationDomainAsync(OrganizationDomain domain)
|
||||
{
|
||||
if (domain.VerifiedDate is not null)
|
||||
{
|
||||
domain.SetLastCheckedDate();
|
||||
await _organizationDomainRepository.ReplaceAsync(domain);
|
||||
throw new ConflictException("Domain has already been verified.");
|
||||
}
|
||||
|
||||
var claimedDomain =
|
||||
await _organizationDomainRepository.GetClaimedDomainsByDomainNameAsync(domain.DomainName);
|
||||
if (claimedDomain.Any())
|
||||
{
|
||||
domain.SetLastCheckedDate();
|
||||
await _organizationDomainRepository.ReplaceAsync(domain);
|
||||
throw new ConflictException("The domain is not available to be claimed.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (await _dnsResolverService.ResolveAsync(domain.DomainName, domain.Txt))
|
||||
{
|
||||
domain.SetVerifiedDate();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("Error verifying Organization domain: {domain}. {errorMessage}",
|
||||
domain.DomainName, e.Message);
|
||||
}
|
||||
|
||||
domain.SetLastCheckedDate();
|
||||
await _organizationDomainRepository.ReplaceAsync(domain);
|
||||
|
||||
await _eventService.LogOrganizationDomainEventAsync(domain,
|
||||
domain.VerifiedDate != null ? EventType.OrganizationDomain_Verified : EventType.OrganizationDomain_NotVerified);
|
||||
return domain;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
||||
|
||||
public class CountNewSmSeatsRequiredQuery : ICountNewSmSeatsRequiredQuery
|
||||
{
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
|
||||
public CountNewSmSeatsRequiredQuery(IOrganizationUserRepository organizationUserRepository,
|
||||
IOrganizationRepository organizationRepository)
|
||||
{
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_organizationRepository = organizationRepository;
|
||||
}
|
||||
|
||||
public async Task<int> CountNewSmSeatsRequiredAsync(Guid organizationId, int usersToAdd)
|
||||
{
|
||||
if (usersToAdd == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
if (organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
if (!organization.UseSecretsManager)
|
||||
{
|
||||
throw new BadRequestException("Organization does not use Secrets Manager");
|
||||
}
|
||||
|
||||
if (!organization.SmSeats.HasValue || organization.SecretsManagerBeta)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var occupiedSmSeats =
|
||||
await _organizationUserRepository.GetOccupiedSmSeatCountByOrganizationIdAsync(organization.Id);
|
||||
|
||||
var availableSmSeats = organization.SmSeats.Value - occupiedSmSeats;
|
||||
|
||||
if (availableSmSeats >= usersToAdd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return usersToAdd - availableSmSeats;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
||||
|
||||
public class DeleteOrganizationUserCommand : IDeleteOrganizationUserCommand
|
||||
{
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
|
||||
public DeleteOrganizationUserCommand(
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IOrganizationService organizationService
|
||||
)
|
||||
{
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_organizationService = organizationService;
|
||||
}
|
||||
|
||||
public async Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, Guid? deletingUserId)
|
||||
{
|
||||
await ValidateDeleteUserAsync(organizationId, organizationUserId);
|
||||
|
||||
await _organizationService.DeleteUserAsync(organizationId, organizationUserId, deletingUserId);
|
||||
}
|
||||
|
||||
public async Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, EventSystemUser eventSystemUser)
|
||||
{
|
||||
await ValidateDeleteUserAsync(organizationId, organizationUserId);
|
||||
|
||||
await _organizationService.DeleteUserAsync(organizationId, organizationUserId, eventSystemUser);
|
||||
}
|
||||
|
||||
private async Task ValidateDeleteUserAsync(Guid organizationId, Guid organizationUserId)
|
||||
{
|
||||
var orgUser = await _organizationUserRepository.GetByIdAsync(organizationUserId);
|
||||
if (orgUser == null || orgUser.OrganizationId != organizationId)
|
||||
{
|
||||
throw new NotFoundException("User not found.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
|
||||
public interface ICountNewSmSeatsRequiredQuery
|
||||
{
|
||||
public Task<int> CountNewSmSeatsRequiredAsync(Guid organizationId, int usersToAdd);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
|
||||
public interface IDeleteOrganizationUserCommand
|
||||
{
|
||||
Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, Guid? deletingUserId);
|
||||
|
||||
Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, EventSystemUser eventSystemUser);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
|
||||
public interface IUpdateOrganizationUserGroupsCommand
|
||||
{
|
||||
Task UpdateUserGroupsAsync(OrganizationUser organizationUser, IEnumerable<Guid> groupIds, Guid? loggedInUserId);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
||||
|
||||
public class UpdateOrganizationUserGroupsCommand : IUpdateOrganizationUserGroupsCommand
|
||||
{
|
||||
private readonly IEventService _eventService;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
|
||||
public UpdateOrganizationUserGroupsCommand(
|
||||
IEventService eventService,
|
||||
IOrganizationService organizationService,
|
||||
IOrganizationUserRepository organizationUserRepository)
|
||||
{
|
||||
_eventService = eventService;
|
||||
_organizationService = organizationService;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
}
|
||||
|
||||
public async Task UpdateUserGroupsAsync(OrganizationUser organizationUser, IEnumerable<Guid> groupIds, Guid? loggedInUserId)
|
||||
{
|
||||
if (loggedInUserId.HasValue)
|
||||
{
|
||||
await _organizationService.ValidateOrganizationUserUpdatePermissions(organizationUser.OrganizationId, organizationUser.Type, null, organizationUser.GetPermissions());
|
||||
}
|
||||
await _organizationUserRepository.UpdateGroupsAsync(organizationUser.Id, groupIds);
|
||||
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_UpdatedGroups);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user