mirror of
https://github.com/bitwarden/server.git
synced 2024-11-28 13:15:12 +01:00
[PM-1033] refactor(wip): make AcceptUserCommand
This commit is contained in:
parent
43df689c7f
commit
dc1319e7fa
@ -12,6 +12,7 @@ using Bit.Core.OrganizationFeatures.OrganizationUsers;
|
|||||||
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
|
using Bit.Infrastructure.EntityFramework.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ public class OrganizationUsersController : Controller
|
|||||||
private readonly IPolicyRepository _policyRepository;
|
private readonly IPolicyRepository _policyRepository;
|
||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
private readonly IUpdateUserResetPasswordEnrollmentCommand _updateUserResetPasswordEnrollmentCommand;
|
private readonly IUpdateUserResetPasswordEnrollmentCommand _updateUserResetPasswordEnrollmentCommand;
|
||||||
|
private readonly IAcceptUserCommand _acceptUserCommand;
|
||||||
|
|
||||||
public OrganizationUsersController(
|
public OrganizationUsersController(
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
@ -40,6 +42,7 @@ public class OrganizationUsersController : Controller
|
|||||||
IUserService userService,
|
IUserService userService,
|
||||||
IPolicyRepository policyRepository,
|
IPolicyRepository policyRepository,
|
||||||
IUpdateUserResetPasswordEnrollmentCommand updateUserResetPasswordEnrollmentCommand,
|
IUpdateUserResetPasswordEnrollmentCommand updateUserResetPasswordEnrollmentCommand,
|
||||||
|
IAcceptUserCommand acceptUserCommand,
|
||||||
ICurrentContext currentContext)
|
ICurrentContext currentContext)
|
||||||
{
|
{
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
@ -50,6 +53,7 @@ public class OrganizationUsersController : Controller
|
|||||||
_userService = userService;
|
_userService = userService;
|
||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
_updateUserResetPasswordEnrollmentCommand = updateUserResetPasswordEnrollmentCommand;
|
_updateUserResetPasswordEnrollmentCommand = updateUserResetPasswordEnrollmentCommand;
|
||||||
|
_acceptUserCommand = acceptUserCommand;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +196,7 @@ public class OrganizationUsersController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _organizationService.InitPendingOrganization(user.Id, orgId, model.Keys.PublicKey, model.Keys.EncryptedPrivateKey, model.CollectionName);
|
await _organizationService.InitPendingOrganization(user.Id, orgId, model.Keys.PublicKey, model.Keys.EncryptedPrivateKey, model.CollectionName);
|
||||||
await _organizationService.AcceptUserAsync(organizationUserId, user, model.Token, _userService);
|
await _acceptUserCommand.AcceptAsync(organizationUserId, user, model.Token);
|
||||||
await _organizationService.ConfirmUserAsync(orgId, organizationUserId, model.Key, user.Id, _userService);
|
await _organizationService.ConfirmUserAsync(orgId, organizationUserId, model.Key, user.Id, _userService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +218,7 @@ public class OrganizationUsersController : Controller
|
|||||||
throw new BadRequestException(string.Empty, "Master Password reset is required, but not provided.");
|
throw new BadRequestException(string.Empty, "Master Password reset is required, but not provided.");
|
||||||
}
|
}
|
||||||
|
|
||||||
await _organizationService.AcceptUserAsync(organizationUserId, user, model.Token, _userService);
|
await _acceptUserCommand.AcceptAsync(organizationUserId, user, model.Token);
|
||||||
|
|
||||||
if (useMasterPasswordPolicy)
|
if (useMasterPasswordPolicy)
|
||||||
{
|
{
|
||||||
@ -310,7 +314,7 @@ public class OrganizationUsersController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("{userId}/reset-password-enrollment")]
|
[HttpPut("{userId}/reset-password-enrollment")]
|
||||||
public async Task PutResetPasswordEnrollment(string orgId, string userId, [FromBody] OrganizationUserResetPasswordEnrollmentRequestModel model)
|
public async Task PutResetPasswordEnrollment(Guid organizationId, Guid userId, [FromBody] OrganizationUserResetPasswordEnrollmentRequestModel model)
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
@ -320,13 +324,13 @@ public class OrganizationUsersController : Controller
|
|||||||
|
|
||||||
var callingUserId = user.Id;
|
var callingUserId = user.Id;
|
||||||
await _updateUserResetPasswordEnrollmentCommand.UpdateAsync(
|
await _updateUserResetPasswordEnrollmentCommand.UpdateAsync(
|
||||||
new Guid(orgId), new Guid(userId), model.ResetPasswordKey, callingUserId);
|
organizationId, userId, model.ResetPasswordKey, callingUserId);
|
||||||
|
|
||||||
//if (orgUser.Status == OrganizationUserStatusType.Invited)
|
var orgUser = await _organizationUserRepository.GetByOrganizationAsync(organizationId, userId);
|
||||||
//{
|
if (orgUser.Status == OrganizationUserStatusType.Invited)
|
||||||
// var user = await _userRepository.GetByIdAsync(userId);
|
{
|
||||||
// await _organizationService.AcceptUserAsync(orgUser, user, _userService);
|
await _acceptUserCommand.AcceptAsync(organizationId, user);
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("{id}/reset-password")]
|
[HttpPut("{id}/reset-password")]
|
||||||
|
@ -0,0 +1,187 @@
|
|||||||
|
using Bit.Core.Entities;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
|
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
|
using Bit.Core.Repositories;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Bit.Core.Settings;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
|
|
||||||
|
namespace Bit.Core.OrganizationFeatures.OrganizationUsers;
|
||||||
|
|
||||||
|
public class AcceptUserCommand : IAcceptUserCommand
|
||||||
|
{
|
||||||
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
|
private readonly IDataProtector _dataProtector;
|
||||||
|
private readonly IMailService _mailService;
|
||||||
|
private readonly IPolicyService _policyService;
|
||||||
|
private readonly IGlobalSettings _globalSettings;
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
|
||||||
|
public AcceptUserCommand(
|
||||||
|
IOrganizationRepository organizationRepository,
|
||||||
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
|
IDataProtector dataProtector,
|
||||||
|
IMailService mailService,
|
||||||
|
IPolicyService policyService,
|
||||||
|
IGlobalSettings globalSettings,
|
||||||
|
IUserService userService)
|
||||||
|
{
|
||||||
|
_organizationRepository = organizationRepository;
|
||||||
|
_organizationUserRepository = organizationUserRepository;
|
||||||
|
_dataProtector = dataProtector;
|
||||||
|
_mailService = mailService;
|
||||||
|
_policyService = policyService;
|
||||||
|
_globalSettings = globalSettings;
|
||||||
|
_userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OrganizationUser> AcceptAsync(Guid organizationUserId, User user, string token)
|
||||||
|
{
|
||||||
|
var orgUser = await _organizationUserRepository.GetByIdAsync(organizationUserId);
|
||||||
|
if (orgUser == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("User invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CoreHelpers.UserInviteTokenIsValid(_dataProtector, token, user.Email, orgUser.Id, _globalSettings))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Invalid token.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var existingOrgUserCount = await _organizationUserRepository.GetCountByOrganizationAsync(
|
||||||
|
orgUser.OrganizationId, user.Email, true);
|
||||||
|
if (existingOrgUserCount > 0)
|
||||||
|
{
|
||||||
|
if (orgUser.Status == OrganizationUserStatusType.Accepted)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Invitation already accepted. You will receive an email when your organization membership is confirmed.");
|
||||||
|
}
|
||||||
|
throw new BadRequestException("You are already part of this organization.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(orgUser.Email) ||
|
||||||
|
!orgUser.Email.Equals(user.Email, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("User email does not match invite.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await AcceptAsync(orgUser, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OrganizationUser> AcceptAsync(string orgIdentifier, User user)
|
||||||
|
{
|
||||||
|
var org = await _organizationRepository.GetByIdentifierAsync(orgIdentifier);
|
||||||
|
if (org == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Organization invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var usersOrgs = await _organizationUserRepository.GetManyByUserAsync(user.Id);
|
||||||
|
var orgUser = usersOrgs.FirstOrDefault(u => u.OrganizationId == org.Id);
|
||||||
|
if (orgUser == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("User not found within organization.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await AcceptAsync(orgUser, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OrganizationUser> AcceptAsync(Guid organizationId, User user)
|
||||||
|
{
|
||||||
|
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
||||||
|
if (org == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Organization invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var usersOrgs = await _organizationUserRepository.GetManyByUserAsync(user.Id);
|
||||||
|
var orgUser = usersOrgs.FirstOrDefault(u => u.OrganizationId == org.Id);
|
||||||
|
if (orgUser == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("User not found within organization.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await AcceptAsync(orgUser, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<OrganizationUser> AcceptAsync(OrganizationUser orgUser, User user)
|
||||||
|
{
|
||||||
|
if (orgUser.Status == OrganizationUserStatusType.Revoked)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Your organization access has been revoked.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orgUser.Status != OrganizationUserStatusType.Invited)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Already accepted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orgUser.Type == OrganizationUserType.Owner || orgUser.Type == OrganizationUserType.Admin)
|
||||||
|
{
|
||||||
|
var org = await _organizationRepository.GetByIdAsync(orgUser.OrganizationId);
|
||||||
|
if (org.PlanType == PlanType.Free)
|
||||||
|
{
|
||||||
|
var adminCount = await _organizationUserRepository.GetCountByFreeOrganizationAdminUserAsync(
|
||||||
|
user.Id);
|
||||||
|
if (adminCount > 0)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("You can only be an admin of one free organization.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce Single Organization Policy of organization user is trying to join
|
||||||
|
var allOrgUsers = await _organizationUserRepository.GetManyByUserAsync(user.Id);
|
||||||
|
var hasOtherOrgs = allOrgUsers.Any(ou => ou.OrganizationId != orgUser.OrganizationId);
|
||||||
|
var invitedSingleOrgPolicies = await _policyService.GetPoliciesApplicableToUserAsync(user.Id,
|
||||||
|
PolicyType.SingleOrg, OrganizationUserStatusType.Invited);
|
||||||
|
|
||||||
|
if (hasOtherOrgs && invitedSingleOrgPolicies.Any(p => p.OrganizationId == orgUser.OrganizationId))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("You may not join this organization until you leave or remove " +
|
||||||
|
"all other organizations.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce Single Organization Policy of other organizations user is a member of
|
||||||
|
var anySingleOrgPolicies = await _policyService.AnyPoliciesApplicableToUserAsync(user.Id,
|
||||||
|
PolicyType.SingleOrg);
|
||||||
|
if (anySingleOrgPolicies)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("You cannot join this organization because you are a member of " +
|
||||||
|
"another organization which forbids it");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce Two Factor Authentication Policy of organization user is trying to join
|
||||||
|
if (!await _userService.TwoFactorIsEnabledAsync(user))
|
||||||
|
{
|
||||||
|
var invitedTwoFactorPolicies = await _policyService.GetPoliciesApplicableToUserAsync(user.Id,
|
||||||
|
PolicyType.TwoFactorAuthentication, OrganizationUserStatusType.Invited);
|
||||||
|
if (invitedTwoFactorPolicies.Any(p => p.OrganizationId == orgUser.OrganizationId))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("You cannot join this organization until you enable " +
|
||||||
|
"two-step login on your user account.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orgUser.Status = OrganizationUserStatusType.Accepted;
|
||||||
|
orgUser.UserId = user.Id;
|
||||||
|
orgUser.Email = null;
|
||||||
|
|
||||||
|
await _organizationUserRepository.ReplaceAsync(orgUser);
|
||||||
|
|
||||||
|
var admins = await _organizationUserRepository.GetManyByMinimumRoleAsync(orgUser.OrganizationId, OrganizationUserType.Admin);
|
||||||
|
var adminEmails = admins.Select(a => a.Email).Distinct().ToList();
|
||||||
|
|
||||||
|
if (adminEmails.Count > 0)
|
||||||
|
{
|
||||||
|
var organization = await _organizationRepository.GetByIdAsync(orgUser.OrganizationId);
|
||||||
|
await _mailService.SendOrganizationAcceptedEmailAsync(organization, user.Email, adminEmails);
|
||||||
|
}
|
||||||
|
|
||||||
|
return orgUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
using Bit.Core.Entities;
|
||||||
|
|
||||||
|
namespace Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
|
|
||||||
|
public interface IAcceptUserCommand
|
||||||
|
{
|
||||||
|
Task<OrganizationUser> AcceptAsync(Guid organizationUserId, User user, string token);
|
||||||
|
|
||||||
|
Task<OrganizationUser> AcceptAsync(string orgIdentifier, User user);
|
||||||
|
|
||||||
|
Task<OrganizationUser> AcceptAsync(Guid organizationId, User user);
|
||||||
|
}
|
||||||
|
|
@ -40,8 +40,6 @@ public interface IOrganizationService
|
|||||||
OrganizationUserType type, bool accessAll, string externalId, IEnumerable<CollectionAccessSelection> collections, IEnumerable<Guid> groups);
|
OrganizationUserType type, bool accessAll, string externalId, IEnumerable<CollectionAccessSelection> collections, IEnumerable<Guid> groups);
|
||||||
Task<IEnumerable<Tuple<OrganizationUser, string>>> ResendInvitesAsync(Guid organizationId, Guid? invitingUserId, IEnumerable<Guid> organizationUsersId);
|
Task<IEnumerable<Tuple<OrganizationUser, string>>> ResendInvitesAsync(Guid organizationId, Guid? invitingUserId, IEnumerable<Guid> organizationUsersId);
|
||||||
Task ResendInviteAsync(Guid organizationId, Guid? invitingUserId, Guid organizationUserId, bool initOrganization = false);
|
Task ResendInviteAsync(Guid organizationId, Guid? invitingUserId, Guid organizationUserId, bool initOrganization = false);
|
||||||
Task<OrganizationUser> AcceptUserAsync(Guid organizationUserId, User user, string token, IUserService userService);
|
|
||||||
Task<OrganizationUser> AcceptUserAsync(string orgIdentifier, User user, IUserService userService);
|
|
||||||
Task<OrganizationUser> ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key,
|
Task<OrganizationUser> ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key,
|
||||||
Guid confirmingUserId, IUserService userService);
|
Guid confirmingUserId, IUserService userService);
|
||||||
Task<List<Tuple<OrganizationUser, string>>> ConfirmUsersAsync(Guid organizationId, Dictionary<Guid, string> keys,
|
Task<List<Tuple<OrganizationUser, string>>> ConfirmUsersAsync(Guid organizationId, Dictionary<Guid, string> keys,
|
||||||
|
@ -1213,154 +1213,6 @@ public class OrganizationService : IOrganizationService
|
|||||||
await _mailService.SendOrganizationInviteEmailAsync(organization.Name, orgUser, new ExpiringToken(token, now.AddDays(5)), organization.PlanType == PlanType.Free, initOrganization);
|
await _mailService.SendOrganizationInviteEmailAsync(organization.Name, orgUser, new ExpiringToken(token, now.AddDays(5)), organization.PlanType == PlanType.Free, initOrganization);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<OrganizationUser> AcceptUserAsync(Guid organizationUserId, User user, string token,
|
|
||||||
IUserService userService)
|
|
||||||
{
|
|
||||||
var orgUser = await _organizationUserRepository.GetByIdAsync(organizationUserId);
|
|
||||||
if (orgUser == null)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("User invalid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CoreHelpers.UserInviteTokenIsValid(_dataProtector, token, user.Email, orgUser.Id, _globalSettings))
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Invalid token.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var existingOrgUserCount = await _organizationUserRepository.GetCountByOrganizationAsync(
|
|
||||||
orgUser.OrganizationId, user.Email, true);
|
|
||||||
if (existingOrgUserCount > 0)
|
|
||||||
{
|
|
||||||
if (orgUser.Status == OrganizationUserStatusType.Accepted)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Invitation already accepted. You will receive an email when your organization membership is confirmed.");
|
|
||||||
}
|
|
||||||
throw new BadRequestException("You are already part of this organization.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(orgUser.Email) ||
|
|
||||||
!orgUser.Email.Equals(user.Email, StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
throw new BadRequestException("User email does not match invite.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return await AcceptUserAsync(orgUser, user, userService);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<OrganizationUser> AcceptUserAsync(string orgIdentifier, User user, IUserService userService)
|
|
||||||
{
|
|
||||||
var org = await _organizationRepository.GetByIdentifierAsync(orgIdentifier);
|
|
||||||
if (org == null)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Organization invalid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var usersOrgs = await _organizationUserRepository.GetManyByUserAsync(user.Id);
|
|
||||||
var orgUser = usersOrgs.FirstOrDefault(u => u.OrganizationId == org.Id);
|
|
||||||
if (orgUser == null)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("User not found within organization.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return await AcceptUserAsync(orgUser, user, userService);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<OrganizationUser> AcceptUserAsync(Guid organizationId, User user, IUserService userService)
|
|
||||||
{
|
|
||||||
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
|
||||||
if (org == null)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Organization invalid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var usersOrgs = await _organizationUserRepository.GetManyByUserAsync(user.Id);
|
|
||||||
var orgUser = usersOrgs.FirstOrDefault(u => u.OrganizationId == org.Id);
|
|
||||||
if (orgUser == null)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("User not found within organization.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return await AcceptUserAsync(orgUser, user, userService);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<OrganizationUser> AcceptUserAsync(OrganizationUser orgUser, User user,
|
|
||||||
IUserService userService)
|
|
||||||
{
|
|
||||||
if (orgUser.Status == OrganizationUserStatusType.Revoked)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Your organization access has been revoked.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (orgUser.Status != OrganizationUserStatusType.Invited)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Already accepted.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (orgUser.Type == OrganizationUserType.Owner || orgUser.Type == OrganizationUserType.Admin)
|
|
||||||
{
|
|
||||||
var org = await GetOrgById(orgUser.OrganizationId);
|
|
||||||
if (org.PlanType == PlanType.Free)
|
|
||||||
{
|
|
||||||
var adminCount = await _organizationUserRepository.GetCountByFreeOrganizationAdminUserAsync(
|
|
||||||
user.Id);
|
|
||||||
if (adminCount > 0)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("You can only be an admin of one free organization.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce Single Organization Policy of organization user is trying to join
|
|
||||||
var allOrgUsers = await _organizationUserRepository.GetManyByUserAsync(user.Id);
|
|
||||||
var hasOtherOrgs = allOrgUsers.Any(ou => ou.OrganizationId != orgUser.OrganizationId);
|
|
||||||
var invitedSingleOrgPolicies = await _policyService.GetPoliciesApplicableToUserAsync(user.Id,
|
|
||||||
PolicyType.SingleOrg, OrganizationUserStatusType.Invited);
|
|
||||||
|
|
||||||
if (hasOtherOrgs && invitedSingleOrgPolicies.Any(p => p.OrganizationId == orgUser.OrganizationId))
|
|
||||||
{
|
|
||||||
throw new BadRequestException("You may not join this organization until you leave or remove " +
|
|
||||||
"all other organizations.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce Single Organization Policy of other organizations user is a member of
|
|
||||||
var anySingleOrgPolicies = await _policyService.AnyPoliciesApplicableToUserAsync(user.Id,
|
|
||||||
PolicyType.SingleOrg);
|
|
||||||
if (anySingleOrgPolicies)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("You cannot join this organization because you are a member of " +
|
|
||||||
"another organization which forbids it");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce Two Factor Authentication Policy of organization user is trying to join
|
|
||||||
if (!await userService.TwoFactorIsEnabledAsync(user))
|
|
||||||
{
|
|
||||||
var invitedTwoFactorPolicies = await _policyService.GetPoliciesApplicableToUserAsync(user.Id,
|
|
||||||
PolicyType.TwoFactorAuthentication, OrganizationUserStatusType.Invited);
|
|
||||||
if (invitedTwoFactorPolicies.Any(p => p.OrganizationId == orgUser.OrganizationId))
|
|
||||||
{
|
|
||||||
throw new BadRequestException("You cannot join this organization until you enable " +
|
|
||||||
"two-step login on your user account.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
orgUser.Status = OrganizationUserStatusType.Accepted;
|
|
||||||
orgUser.UserId = user.Id;
|
|
||||||
orgUser.Email = null;
|
|
||||||
|
|
||||||
await _organizationUserRepository.ReplaceAsync(orgUser);
|
|
||||||
|
|
||||||
var admins = await _organizationUserRepository.GetManyByMinimumRoleAsync(orgUser.OrganizationId, OrganizationUserType.Admin);
|
|
||||||
var adminEmails = admins.Select(a => a.Email).Distinct().ToList();
|
|
||||||
|
|
||||||
if (adminEmails.Count > 0)
|
|
||||||
{
|
|
||||||
var organization = await _organizationRepository.GetByIdAsync(orgUser.OrganizationId);
|
|
||||||
await _mailService.SendOrganizationAcceptedEmailAsync(organization, user.Email, adminEmails);
|
|
||||||
}
|
|
||||||
|
|
||||||
return orgUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<OrganizationUser> ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key,
|
public async Task<OrganizationUser> ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key,
|
||||||
Guid confirmingUserId, IUserService userService)
|
Guid confirmingUserId, IUserService userService)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user