mirror of
https://github.com/bitwarden/server.git
synced 2024-11-24 12:35:25 +01:00
[SM-1211] Adding API endpoint to send out Access Request for SM to Admins, addi… (#4155)
* Adding API endpoint to send out Access Request for SM to Admins, adding email template * Fixing email template HTML, adding tests * fixing tests * fixing lint * Moving files to proper locations * fixing build error relating to not removing some old code * Updating namespaces and removing unused using statements * Dependency injection fix * Fixing tests and moving them to proper files * lint * format fixes * dotnet format fix * small fixes * removing using directive's that aren't needed * Update bitwarden_license/test/Commercial.Core.Test/SecretsManager/Commands/PasswordManager/RequestSMAccessCommandTests.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/MailTemplates/Handlebars/SecretsManagerAccessRequest.text.hbs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update bitwarden_license/src/Commercial.Core/SecretsManager/Commands/PasswordManager/RequestSMAccessCommand.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Changes requested by Thomas * Lint fixes * Suggested changes from Maceij * Current state of tests * Fixing tests and getting the core.csproj file from main * Reverting csproj file change * Removing usings directory * dotnet format * Fixing test * Update bitwarden_license/test/Commercial.Core.Test/SecretsManager/Commands/Requests/RequestSMAccessCommandTests.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update test/Api.Test/SecretsManager/Controllers/RequestSMAccessControllerTests.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Thomas requested changes * Fixing 500 error when user name is null * Prettier error message if user sends over an whitespace string * Fixing word wrapping issue in email contents --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
This commit is contained in:
parent
aba2f023cd
commit
9560a32495
@ -0,0 +1,34 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.SecretsManager.Commands.Requests.Interfaces;
|
||||
using Bit.Core.Services;
|
||||
|
||||
namespace Bit.Commercial.Core.SecretsManager.Commands.Requests;
|
||||
|
||||
public class RequestSMAccessCommand : IRequestSMAccessCommand
|
||||
{
|
||||
private readonly IMailService _mailService;
|
||||
|
||||
public RequestSMAccessCommand(
|
||||
IMailService mailService)
|
||||
{
|
||||
_mailService = mailService;
|
||||
}
|
||||
|
||||
public async Task SendRequestAccessToSM(Organization organization, ICollection<OrganizationUserUserDetails> orgUsers, User user, string emailContent)
|
||||
{
|
||||
var emailList = orgUsers.Where(o => o.Type <= OrganizationUserType.Admin)
|
||||
.Select(a => a.Email).Distinct().ToList();
|
||||
|
||||
if (!emailList.Any())
|
||||
{
|
||||
throw new BadRequestException("The organization is in an invalid state. Please contact Customer Support.");
|
||||
}
|
||||
|
||||
var userRequestingAccess = user.Name ?? user.Email;
|
||||
await _mailService.SendRequestSMAccessToAdminEmailAsync(emailList, organization.Name, userRequestingAccess, emailContent);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ using Bit.Commercial.Core.SecretsManager.Commands.AccessPolicies;
|
||||
using Bit.Commercial.Core.SecretsManager.Commands.AccessTokens;
|
||||
using Bit.Commercial.Core.SecretsManager.Commands.Porting;
|
||||
using Bit.Commercial.Core.SecretsManager.Commands.Projects;
|
||||
using Bit.Commercial.Core.SecretsManager.Commands.Requests;
|
||||
using Bit.Commercial.Core.SecretsManager.Commands.Secrets;
|
||||
using Bit.Commercial.Core.SecretsManager.Commands.ServiceAccounts;
|
||||
using Bit.Commercial.Core.SecretsManager.Commands.Trash;
|
||||
@ -18,6 +19,7 @@ using Bit.Core.SecretsManager.Commands.AccessPolicies.Interfaces;
|
||||
using Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces;
|
||||
using Bit.Core.SecretsManager.Commands.Porting.Interfaces;
|
||||
using Bit.Core.SecretsManager.Commands.Projects.Interfaces;
|
||||
using Bit.Core.SecretsManager.Commands.Requests.Interfaces;
|
||||
using Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
|
||||
using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
|
||||
using Bit.Core.SecretsManager.Commands.Trash.Interfaces;
|
||||
@ -56,6 +58,7 @@ public static class SecretsManagerCollectionExtensions
|
||||
services.AddScoped<IUpdateSecretCommand, UpdateSecretCommand>();
|
||||
services.AddScoped<IDeleteSecretCommand, DeleteSecretCommand>();
|
||||
services.AddScoped<ICreateProjectCommand, CreateProjectCommand>();
|
||||
services.AddScoped<IRequestSMAccessCommand, RequestSMAccessCommand>();
|
||||
services.AddScoped<IUpdateProjectCommand, UpdateProjectCommand>();
|
||||
services.AddScoped<IDeleteProjectCommand, DeleteProjectCommand>();
|
||||
services.AddScoped<ICreateServiceAccountCommand, CreateServiceAccountCommand>();
|
||||
|
@ -0,0 +1,96 @@
|
||||
using Bit.Commercial.Core.SecretsManager.Commands.Requests;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Commercial.Core.Test.SecretsManager.Commands.Requests;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class RequestSMAccessCommandTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SendRequestAccessToSM_Success(
|
||||
User user,
|
||||
Organization organization,
|
||||
ICollection<OrganizationUserUserDetails> orgUsers,
|
||||
string emailContent,
|
||||
SutProvider<RequestSMAccessCommand> sutProvider)
|
||||
{
|
||||
foreach (var userDetails in orgUsers)
|
||||
{
|
||||
userDetails.Type = OrganizationUserType.Admin;
|
||||
}
|
||||
|
||||
orgUsers.First().Type = OrganizationUserType.Owner;
|
||||
|
||||
await sutProvider.Sut.SendRequestAccessToSM(organization, orgUsers, user, emailContent);
|
||||
|
||||
var adminEmailList = orgUsers
|
||||
.Where(o => o.Type <= OrganizationUserType.Admin)
|
||||
.Select(a => a.Email)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendRequestSMAccessToAdminEmailAsync(Arg.Is(AssertHelper.AssertPropertyEqual(adminEmailList)), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SendRequestAccessToSM_NoAdmins_ThrowsBadRequestException(
|
||||
User user,
|
||||
Organization organization,
|
||||
ICollection<OrganizationUserUserDetails> orgUsers,
|
||||
string emailContent,
|
||||
SutProvider<RequestSMAccessCommand> sutProvider)
|
||||
{
|
||||
// Set OrgUsers so they are only users, no admins or owners
|
||||
foreach (OrganizationUserUserDetails userDetails in orgUsers)
|
||||
{
|
||||
userDetails.Type = OrganizationUserType.User;
|
||||
}
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SendRequestAccessToSM(organization, orgUsers, user, emailContent));
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SendRequestAccessToSM_SomeAdmins_EmailListIsAsExpected(
|
||||
User user,
|
||||
Organization organization,
|
||||
ICollection<OrganizationUserUserDetails> orgUsers,
|
||||
string emailContent,
|
||||
SutProvider<RequestSMAccessCommand> sutProvider)
|
||||
{
|
||||
foreach (OrganizationUserUserDetails userDetails in orgUsers)
|
||||
{
|
||||
userDetails.Type = OrganizationUserType.User;
|
||||
}
|
||||
|
||||
// Make the first orgUser an admin so it's a mix of Admin + Users
|
||||
orgUsers.First().Type = OrganizationUserType.Admin;
|
||||
|
||||
var adminEmailList = orgUsers
|
||||
.Where(o => o.Type == OrganizationUserType.Admin) // Filter by Admin type
|
||||
.Select(a => a.Email)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
await sutProvider.Sut.SendRequestAccessToSM(organization, orgUsers, user, emailContent);
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendRequestSMAccessToAdminEmailAsync(Arg.Is(AssertHelper.AssertPropertyEqual(adminEmailList)), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>());
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
using Bit.Api.SecretsManager.Models.Request;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.SecretsManager.Commands.Requests.Interfaces;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.SecretsManager.Controllers;
|
||||
|
||||
[Route("request-access")]
|
||||
[Authorize("Web")]
|
||||
public class RequestSMAccessController : Controller
|
||||
{
|
||||
private readonly IRequestSMAccessCommand _requestSMAccessCommand;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
public RequestSMAccessController(
|
||||
IRequestSMAccessCommand requestSMAccessCommand, IUserService userService, IOrganizationRepository organizationRepository, IOrganizationUserRepository organizationUserRepository, ICurrentContext currentContext)
|
||||
{
|
||||
_requestSMAccessCommand = requestSMAccessCommand;
|
||||
_userService = userService;
|
||||
_organizationRepository = organizationRepository;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
||||
[HttpPost("request-sm-access")]
|
||||
public async Task RequestSMAccessFromAdmins([FromBody] RequestSMAccessRequestModel model)
|
||||
{
|
||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
if (!await _currentContext.OrganizationUser(model.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var organization = await _organizationRepository.GetByIdAsync(model.OrganizationId);
|
||||
if (organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organization.Id);
|
||||
await _requestSMAccessCommand.SendRequestAccessToSM(organization, orgUsers, user, model.EmailContent);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Bit.Api.SecretsManager.Models.Request;
|
||||
|
||||
public class RequestSMAccessRequestModel
|
||||
{
|
||||
[Required]
|
||||
public Guid OrganizationId { get; set; }
|
||||
[Required(ErrorMessage = "Add a note is a required field")]
|
||||
public string EmailContent { get; set; }
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
{{#>FullHtmlLayout}}
|
||||
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
|
||||
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
|
||||
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none;" valign="top">
|
||||
{{UserNameRequestingAccess}} has requested access to secrets manager for {{OrgName}}: <br /><br />
|
||||
<pre style="white-space: pre-wrap; word-wrap: break-word; background-color: #ECECEC; max-width: 700px; border-radius: 10px; padding: 1em; margin-bottom: 2em;">{{EmailContent}} - {{UserNameRequestingAccess}}</pre>
|
||||
</td>
|
||||
<br/>
|
||||
</tr>
|
||||
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
|
||||
<td class="content-block" style="margin-bottom:1em; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none;" valign="top" align="left">
|
||||
<a href="https://bitwarden.com/contact-sales/?utm_source=sm_request_access_email&utm_medium=email" clicktracking=off target="_blank" rel="noopener" style="color: #ffffff; text-decoration: none; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background-color: #175DDC; border-color: #175DDC; border-style: solid; border-width: 10px 20px; margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
|
||||
Contact Bitwarden
|
||||
</a>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="margin-top:1em; margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
|
||||
<td class="content-block last" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none; font-weight: bold;" valign="top">
|
||||
<br/> Stay safe and secure,<br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;" />
|
||||
The Bitwarden Team
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
{{/FullHtmlLayout}}
|
@ -0,0 +1,17 @@
|
||||
{{#>FullTextLayout}}
|
||||
|
||||
{{UserNameRequestingAccess}} has requested access to secrets manager for {{OrgName}}:
|
||||
|
||||
============
|
||||
|
||||
{{EmailContent}} - {{UserNameRequestingAccess}}
|
||||
|
||||
============
|
||||
|
||||
Contact Bitwarden (https://bitwarden.com/contact-sales/?utm_source=sm_request_access_email&utm_medium=email)
|
||||
|
||||
============
|
||||
|
||||
Stay safe and secure,
|
||||
The Bitwarden Team
|
||||
{{/FullTextLayout}}
|
@ -0,0 +1,10 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Commands.Requests.Interfaces;
|
||||
|
||||
public interface IRequestSMAccessCommand
|
||||
{
|
||||
Task SendRequestAccessToSM(Organization organization, ICollection<OrganizationUserUserDetails> orgUsers, User user, string emailContent);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using Bit.Core.Models.Mail;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Models.Mail;
|
||||
|
||||
public class RequestSecretsManagerAccessViewModel : BaseMailModel
|
||||
{
|
||||
public string UserNameRequestingAccess { get; set; }
|
||||
public string OrgName { get; set; }
|
||||
public string EmailContent { get; set; }
|
||||
}
|
@ -81,5 +81,6 @@ public interface IMailService
|
||||
Task SendTrialInitiationEmailAsync(string email);
|
||||
Task SendInitiateDeletProviderEmailAsync(string email, Provider provider, string token);
|
||||
Task SendInitiateDeleteOrganzationEmailAsync(string email, Organization organization, string token);
|
||||
Task SendRequestSMAccessToAdminEmailAsync(IEnumerable<string> adminEmails, string organizationName, string userRequestingAccess, string emailContent);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ using Bit.Core.Entities;
|
||||
using Bit.Core.Models.Mail;
|
||||
using Bit.Core.Models.Mail.FamiliesForEnterprise;
|
||||
using Bit.Core.Models.Mail.Provider;
|
||||
using Bit.Core.SecretsManager.Models.Mail;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Utilities;
|
||||
using HandlebarsDotNet;
|
||||
@ -395,6 +396,20 @@ public class HandlebarsMailService : IMailService
|
||||
await _mailDeliveryService.SendEmailAsync(message);
|
||||
}
|
||||
|
||||
public async Task SendRequestSMAccessToAdminEmailAsync(IEnumerable<string> emails, string organizationName, string requestingUserName, string emailContent)
|
||||
{
|
||||
var message = CreateDefaultMessage("Access Requested for Secrets Manager", emails);
|
||||
var model = new RequestSecretsManagerAccessViewModel
|
||||
{
|
||||
OrgName = CoreHelpers.SanitizeForEmail(organizationName, false),
|
||||
UserNameRequestingAccess = CoreHelpers.SanitizeForEmail(requestingUserName, false),
|
||||
EmailContent = CoreHelpers.SanitizeForEmail(emailContent, false),
|
||||
};
|
||||
await AddMessageContentAsync(message, "SecretsManagerAccessRequest", model);
|
||||
message.Category = "SecretsManagerAccessRequest";
|
||||
await _mailDeliveryService.SendEmailAsync(message);
|
||||
}
|
||||
|
||||
public async Task SendNewDeviceLoggedInEmail(string email, string deviceType, DateTime timestamp, string ip)
|
||||
{
|
||||
var message = CreateDefaultMessage($"New Device Logged In From {deviceType}", email);
|
||||
|
@ -280,5 +280,6 @@ public class NoopMailService : IMailService
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
public Task SendRequestSMAccessToAdminEmailAsync(IEnumerable<string> adminEmails, string organizationName, string userRequestingAccess, string emailContent) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,86 @@
|
||||
using System.Security.Claims;
|
||||
using Bit.Api.SecretsManager.Controllers;
|
||||
using Bit.Api.SecretsManager.Models.Request;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.SecretsManager.Commands.Requests.Interfaces;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ReturnsExtensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.SecretsManager.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(RequestSMAccessController))]
|
||||
[SutProviderCustomize]
|
||||
public class RequestSMAccessControllerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RequestSMAccessFromAdmins_WhenSendingNoModel_ShouldThrowNotFoundException(
|
||||
User user, SutProvider<RequestSMAccessController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdentifierAsync(Arg.Any<string>()).ReturnsNullForAnyArgs();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.RequestSMAccessFromAdmins(new RequestSMAccessRequestModel()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RequestSMAccessFromAdmins_WhenSendingValidData_ShouldSucceed(
|
||||
User user,
|
||||
RequestSMAccessRequestModel model,
|
||||
Core.AdminConsole.Entities.Organization org,
|
||||
ICollection<OrganizationUserUserDetails> orgUsers,
|
||||
SutProvider<RequestSMAccessController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(model.OrganizationId).Returns(org);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(org.Id).Returns(orgUsers);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(model.OrganizationId).Returns(true);
|
||||
|
||||
await sutProvider.Sut.RequestSMAccessFromAdmins(model);
|
||||
|
||||
//Also check that the command was called
|
||||
await sutProvider.GetDependency<IRequestSMAccessCommand>()
|
||||
.Received(1)
|
||||
.SendRequestAccessToSM(org, orgUsers, user, model.EmailContent);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RequestSMAccessFromAdmins_WhenUserInvalid_ShouldThrowBadRequestException(RequestSMAccessRequestModel model, SutProvider<RequestSMAccessController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).ReturnsNullForAnyArgs();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(() => sutProvider.Sut.RequestSMAccessFromAdmins(model));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RequestSMAccessFromAdmins_WhenOrgInvalid_ShouldThrowNotFoundException(RequestSMAccessRequestModel model, User user, SutProvider<RequestSMAccessController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdentifierAsync(Arg.Any<string>()).ReturnsNullForAnyArgs();
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).ReturnsForAnyArgs(user);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(model.OrganizationId).Returns(true);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.RequestSMAccessFromAdmins(model));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RequestSMAccessFromAdmins_WhenOrgUserInvalid_ShouldThrowNotFoundException(RequestSMAccessRequestModel model, User user, SutProvider<RequestSMAccessController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdentifierAsync(Arg.Any<string>()).ReturnsNullForAnyArgs();
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).ReturnsForAnyArgs(user);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(model.OrganizationId).Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.RequestSMAccessFromAdmins(model));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user