mirror of
https://github.com/bitwarden/server
synced 2026-01-02 00:23:40 +00:00
* Added Auto confirm policy enforcement requirement. Includes strict single org enforcement along with blocking provider users from joining orgs with auto confirm enabled.
151 lines
6.0 KiB
C#
151 lines
6.0 KiB
C#
// FIXME: Update this file to be null safe and then delete the line below
|
|
#nullable disable
|
|
|
|
using Bit.Core.AdminConsole.Enums;
|
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
|
using Bit.Core.AdminConsole.Services;
|
|
using Bit.Core.Auth.Models.Business.Tokenables;
|
|
using Bit.Core.Entities;
|
|
using Bit.Core.Enums;
|
|
using Bit.Core.Exceptions;
|
|
using Bit.Core.Models.Data;
|
|
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
|
using Bit.Core.Repositories;
|
|
using Bit.Core.Services;
|
|
using Bit.Core.Settings;
|
|
using Bit.Core.Tokens;
|
|
using Microsoft.AspNetCore.DataProtection;
|
|
|
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
|
|
|
public class InitPendingOrganizationCommand : IInitPendingOrganizationCommand
|
|
{
|
|
|
|
private readonly IOrganizationService _organizationService;
|
|
private readonly ICollectionRepository _collectionRepository;
|
|
private readonly IOrganizationRepository _organizationRepository;
|
|
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
|
|
private readonly IDataProtector _dataProtector;
|
|
private readonly IGlobalSettings _globalSettings;
|
|
private readonly IPolicyService _policyService;
|
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
|
private readonly IFeatureService _featureService;
|
|
private readonly IPolicyRequirementQuery _policyRequirementQuery;
|
|
|
|
public InitPendingOrganizationCommand(
|
|
IOrganizationService organizationService,
|
|
ICollectionRepository collectionRepository,
|
|
IOrganizationRepository organizationRepository,
|
|
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
|
|
IDataProtectionProvider dataProtectionProvider,
|
|
IGlobalSettings globalSettings,
|
|
IPolicyService policyService,
|
|
IOrganizationUserRepository organizationUserRepository,
|
|
IFeatureService featureService,
|
|
IPolicyRequirementQuery policyRequirementQuery
|
|
)
|
|
{
|
|
_organizationService = organizationService;
|
|
_collectionRepository = collectionRepository;
|
|
_organizationRepository = organizationRepository;
|
|
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
|
|
_dataProtector = dataProtectionProvider.CreateProtector(OrgUserInviteTokenable.DataProtectorPurpose);
|
|
_globalSettings = globalSettings;
|
|
_policyService = policyService;
|
|
_organizationUserRepository = organizationUserRepository;
|
|
_featureService = featureService;
|
|
_policyRequirementQuery = policyRequirementQuery;
|
|
}
|
|
|
|
public async Task InitPendingOrganizationAsync(User user, Guid organizationId, Guid organizationUserId, string publicKey, string privateKey, string collectionName, string emailToken)
|
|
{
|
|
await ValidateSignUpPoliciesAsync(user.Id);
|
|
|
|
var orgUser = await _organizationUserRepository.GetByIdAsync(organizationUserId);
|
|
if (orgUser == null)
|
|
{
|
|
throw new BadRequestException("User invalid.");
|
|
}
|
|
|
|
var tokenValid = ValidateInviteToken(orgUser, user, emailToken);
|
|
|
|
if (!tokenValid)
|
|
{
|
|
throw new BadRequestException("Invalid token");
|
|
}
|
|
|
|
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
|
|
|
if (org.Enabled)
|
|
{
|
|
throw new BadRequestException("Organization is already enabled.");
|
|
}
|
|
|
|
if (org.Status != OrganizationStatusType.Pending)
|
|
{
|
|
throw new BadRequestException("Organization is not on a Pending status.");
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(org.PublicKey))
|
|
{
|
|
throw new BadRequestException("Organization already has a Public Key.");
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(org.PrivateKey))
|
|
{
|
|
throw new BadRequestException("Organization already has a Private Key.");
|
|
}
|
|
|
|
org.Enabled = true;
|
|
org.Status = OrganizationStatusType.Created;
|
|
org.PublicKey = publicKey;
|
|
org.PrivateKey = privateKey;
|
|
|
|
await _organizationService.UpdateAsync(org);
|
|
|
|
if (!string.IsNullOrWhiteSpace(collectionName))
|
|
{
|
|
// give the owner Can Manage access over the default collection
|
|
List<CollectionAccessSelection> defaultOwnerAccess =
|
|
[new CollectionAccessSelection { Id = orgUser.Id, HidePasswords = false, ReadOnly = false, Manage = true }];
|
|
|
|
var defaultCollection = new Collection
|
|
{
|
|
Name = collectionName,
|
|
OrganizationId = org.Id
|
|
};
|
|
await _collectionRepository.CreateAsync(defaultCollection, null, defaultOwnerAccess);
|
|
}
|
|
}
|
|
|
|
private async Task ValidateSignUpPoliciesAsync(Guid ownerId)
|
|
{
|
|
if (_featureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
|
|
{
|
|
var requirement = await _policyRequirementQuery.GetAsync<AutomaticUserConfirmationPolicyRequirement>(ownerId);
|
|
|
|
if (requirement.CannotCreateNewOrganization())
|
|
{
|
|
throw new BadRequestException("You may not create an organization. You belong to an organization " +
|
|
"which has a policy that prohibits you from being a member of any other organization.");
|
|
}
|
|
}
|
|
|
|
var anySingleOrgPolicies = await _policyService.AnyPoliciesApplicableToUserAsync(ownerId, PolicyType.SingleOrg);
|
|
if (anySingleOrgPolicies)
|
|
{
|
|
throw new BadRequestException("You may not create an organization. You belong to an organization " +
|
|
"which has a policy that prohibits you from being a member of any other organization.");
|
|
}
|
|
}
|
|
|
|
private bool ValidateInviteToken(OrganizationUser orgUser, User user, string emailToken)
|
|
{
|
|
var tokenValid = OrgUserInviteTokenable.ValidateOrgUserInviteStringToken(
|
|
_orgUserInviteTokenDataFactory, emailToken, orgUser);
|
|
|
|
return tokenValid;
|
|
}
|
|
}
|