mirror of
https://github.com/bitwarden/server.git
synced 2025-02-01 23:31:41 +01:00
Fix/f4e multiple sponsorships (#1838)
* Use sponosorship from validate to redeem * Update tests * Format
This commit is contained in:
parent
452677e441
commit
8ce4d56a91
@ -68,14 +68,16 @@ namespace Bit.Api.Controllers
|
|||||||
[SelfHosted(NotSelfHostedOnly = true)]
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task<bool> PreValidateSponsorshipToken([FromQuery] string sponsorshipToken)
|
public async Task<bool> PreValidateSponsorshipToken([FromQuery] string sponsorshipToken)
|
||||||
{
|
{
|
||||||
return await _organizationsSponsorshipService.ValidateRedemptionTokenAsync(sponsorshipToken, (await CurrentUser).Email);
|
return (await _organizationsSponsorshipService.ValidateRedemptionTokenAsync(sponsorshipToken, (await CurrentUser).Email)).valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("redeem")]
|
[HttpPost("redeem")]
|
||||||
[SelfHosted(NotSelfHostedOnly = true)]
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
public async Task RedeemSponsorship([FromQuery] string sponsorshipToken, [FromBody] OrganizationSponsorshipRedeemRequestModel model)
|
public async Task RedeemSponsorship([FromQuery] string sponsorshipToken, [FromBody] OrganizationSponsorshipRedeemRequestModel model)
|
||||||
{
|
{
|
||||||
if (!await _organizationsSponsorshipService.ValidateRedemptionTokenAsync(sponsorshipToken, (await CurrentUser).Email))
|
var (valid, sponsorship) = await _organizationsSponsorshipService.ValidateRedemptionTokenAsync(sponsorshipToken, (await CurrentUser).Email);
|
||||||
|
|
||||||
|
if (!valid)
|
||||||
{
|
{
|
||||||
throw new BadRequestException("Failed to parse sponsorship token.");
|
throw new BadRequestException("Failed to parse sponsorship token.");
|
||||||
}
|
}
|
||||||
@ -86,8 +88,7 @@ namespace Bit.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _organizationsSponsorshipService.SetUpSponsorshipAsync(
|
await _organizationsSponsorshipService.SetUpSponsorshipAsync(
|
||||||
await _organizationSponsorshipRepository
|
sponsorship,
|
||||||
.GetByOfferedToEmailAsync((await CurrentUser).Email),
|
|
||||||
// Check org to sponsor's product type
|
// Check org to sponsor's product type
|
||||||
await _organizationRepository.GetByIdAsync(model.SponsoredOrganizationId));
|
await _organizationRepository.GetByIdAsync(model.SponsoredOrganizationId));
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,5 @@ namespace Bit.Core.Repositories
|
|||||||
{
|
{
|
||||||
Task<OrganizationSponsorship> GetBySponsoringOrganizationUserIdAsync(Guid sponsoringOrganizationUserId);
|
Task<OrganizationSponsorship> GetBySponsoringOrganizationUserIdAsync(Guid sponsoringOrganizationUserId);
|
||||||
Task<OrganizationSponsorship> GetBySponsoredOrganizationIdAsync(Guid sponsoredOrganizationId);
|
Task<OrganizationSponsorship> GetBySponsoredOrganizationIdAsync(Guid sponsoredOrganizationId);
|
||||||
Task<OrganizationSponsorship> GetByOfferedToEmailAsync(string email);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
public interface IOrganizationSponsorshipService
|
public interface IOrganizationSponsorshipService
|
||||||
{
|
{
|
||||||
Task<bool> ValidateRedemptionTokenAsync(string encryptedToken, string currentUserEmail);
|
Task<(bool valid, OrganizationSponsorship sponsorship)> ValidateRedemptionTokenAsync(string encryptedToken, string currentUserEmail);
|
||||||
Task OfferSponsorshipAsync(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser,
|
Task OfferSponsorshipAsync(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser,
|
||||||
PlanSponsorshipType sponsorshipType, string sponsoredEmail, string friendlyName, string sponsoringUserEmail);
|
PlanSponsorshipType sponsorshipType, string sponsoredEmail, string friendlyName, string sponsoringUserEmail);
|
||||||
Task ResendSponsorshipOfferAsync(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser,
|
Task ResendSponsorshipOfferAsync(Organization sponsoringOrg, OrganizationUser sponsoringOrgUser,
|
||||||
|
@ -37,11 +37,11 @@ namespace Bit.Core.Services
|
|||||||
_dataProtector = dataProtectionProvider.CreateProtector("OrganizationSponsorshipServiceDataProtector");
|
_dataProtector = dataProtectionProvider.CreateProtector("OrganizationSponsorshipServiceDataProtector");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ValidateRedemptionTokenAsync(string encryptedToken, string sponsoredUserEmail)
|
public async Task<(bool valid, OrganizationSponsorship sponsorship)> ValidateRedemptionTokenAsync(string encryptedToken, string sponsoredUserEmail)
|
||||||
{
|
{
|
||||||
if (!encryptedToken.StartsWith(TokenClearTextPrefix) || sponsoredUserEmail == null)
|
if (!encryptedToken.StartsWith(TokenClearTextPrefix) || sponsoredUserEmail == null)
|
||||||
{
|
{
|
||||||
return false;
|
return (false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var decryptedToken = _dataProtector.Unprotect(encryptedToken[TokenClearTextPrefix.Length..]);
|
var decryptedToken = _dataProtector.Unprotect(encryptedToken[TokenClearTextPrefix.Length..]);
|
||||||
@ -49,7 +49,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
if (dataParts.Length != 3)
|
if (dataParts.Length != 3)
|
||||||
{
|
{
|
||||||
return false;
|
return (false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataParts[0].Equals(FamiliesForEnterpriseTokenName))
|
if (dataParts[0].Equals(FamiliesForEnterpriseTokenName))
|
||||||
@ -57,7 +57,7 @@ namespace Bit.Core.Services
|
|||||||
if (!Guid.TryParse(dataParts[1], out Guid sponsorshipId) ||
|
if (!Guid.TryParse(dataParts[1], out Guid sponsorshipId) ||
|
||||||
!Enum.TryParse<PlanSponsorshipType>(dataParts[2], true, out var sponsorshipType))
|
!Enum.TryParse<PlanSponsorshipType>(dataParts[2], true, out var sponsorshipType))
|
||||||
{
|
{
|
||||||
return false;
|
return (false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var sponsorship = await _organizationSponsorshipRepository.GetByIdAsync(sponsorshipId);
|
var sponsorship = await _organizationSponsorshipRepository.GetByIdAsync(sponsorshipId);
|
||||||
@ -65,13 +65,13 @@ namespace Bit.Core.Services
|
|||||||
sponsorship.PlanSponsorshipType != sponsorshipType ||
|
sponsorship.PlanSponsorshipType != sponsorshipType ||
|
||||||
sponsorship.OfferedToEmail != sponsoredUserEmail)
|
sponsorship.OfferedToEmail != sponsoredUserEmail)
|
||||||
{
|
{
|
||||||
return false;
|
return (false, sponsorship);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return (true, sponsorship);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return (false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string RedemptionToken(Guid sponsorshipId, PlanSponsorshipType sponsorshipType) =>
|
private string RedemptionToken(Guid sponsorshipId, PlanSponsorshipType sponsorshipType) =>
|
||||||
|
@ -48,21 +48,5 @@ namespace Bit.Infrastructure.Dapper.Repositories
|
|||||||
return results.SingleOrDefault();
|
return results.SingleOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<OrganizationSponsorship> GetByOfferedToEmailAsync(string offeredToEmail)
|
|
||||||
{
|
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
|
||||||
{
|
|
||||||
var results = await connection.QueryAsync<OrganizationSponsorship>(
|
|
||||||
"[dbo].[OrganizationSponsorship_ReadByOfferedToEmail]",
|
|
||||||
new
|
|
||||||
{
|
|
||||||
OfferedToEmail = offeredToEmail
|
|
||||||
},
|
|
||||||
commandType: CommandType.StoredProcedure);
|
|
||||||
|
|
||||||
return results.SingleOrDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ namespace Bit.Api.Test.Controllers
|
|||||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||||
.Returns(user);
|
.Returns(user);
|
||||||
sutProvider.GetDependency<IOrganizationSponsorshipService>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
sutProvider.GetDependency<IOrganizationSponsorshipService>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
||||||
user.Email).Returns(false);
|
user.Email).Returns((false, null));
|
||||||
|
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||||
sutProvider.Sut.RedeemSponsorship(sponsorshipToken, model));
|
sutProvider.Sut.RedeemSponsorship(sponsorshipToken, model));
|
||||||
@ -59,13 +59,14 @@ namespace Bit.Api.Test.Controllers
|
|||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
public async Task RedeemSponsorship_NotSponsoredOrgOwner_ThrowsBadRequest(string sponsorshipToken, User user,
|
public async Task RedeemSponsorship_NotSponsoredOrgOwner_ThrowsBadRequest(string sponsorshipToken, User user,
|
||||||
OrganizationSponsorshipRedeemRequestModel model, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
OrganizationSponsorship sponsorship, OrganizationSponsorshipRedeemRequestModel model,
|
||||||
|
SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||||
.Returns(user);
|
.Returns(user);
|
||||||
sutProvider.GetDependency<IOrganizationSponsorshipService>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
sutProvider.GetDependency<IOrganizationSponsorshipService>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
||||||
user.Email).Returns(true);
|
user.Email).Returns((true, sponsorship));
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.SponsoredOrganizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.SponsoredOrganizationId).Returns(false);
|
||||||
|
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||||
@ -79,12 +80,34 @@ namespace Bit.Api.Test.Controllers
|
|||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
public async Task PreValidateSponsorshipToken_ValidatesToken_Success(string sponsorshipToken, User user,
|
public async Task RedeemSponsorship_NotSponsoredOrgOwner_Success(string sponsorshipToken, User user,
|
||||||
SutProvider<OrganizationSponsorshipsController> sutProvider)
|
OrganizationSponsorship sponsorship, Organization sponsoringOrganization,
|
||||||
|
OrganizationSponsorshipRedeemRequestModel model, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||||
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||||
.Returns(user);
|
.Returns(user);
|
||||||
|
sutProvider.GetDependency<IOrganizationSponsorshipService>().ValidateRedemptionTokenAsync(sponsorshipToken,
|
||||||
|
user.Email).Returns((true, sponsorship));
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.SponsoredOrganizationId).Returns(true);
|
||||||
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(model.SponsoredOrganizationId).Returns(sponsoringOrganization);
|
||||||
|
|
||||||
|
await sutProvider.Sut.RedeemSponsorship(sponsorshipToken, model);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IOrganizationSponsorshipService>().Received(1)
|
||||||
|
.SetUpSponsorshipAsync(sponsorship, sponsoringOrganization);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task PreValidateSponsorshipToken_ValidatesToken_Success(string sponsorshipToken, User user,
|
||||||
|
OrganizationSponsorship sponsorship, SutProvider<OrganizationSponsorshipsController> sutProvider)
|
||||||
|
{
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(user.Id);
|
||||||
|
sutProvider.GetDependency<IUserService>().GetUserByIdAsync(user.Id)
|
||||||
|
.Returns(user);
|
||||||
|
sutProvider.GetDependency<IOrganizationSponsorshipService>()
|
||||||
|
.ValidateRedemptionTokenAsync(sponsorshipToken, user.Email).Returns((true, sponsorship));
|
||||||
|
|
||||||
await sutProvider.Sut.PreValidateSponsorshipToken(sponsorshipToken);
|
await sutProvider.Sut.PreValidateSponsorshipToken(sponsorshipToken);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user