mirror of
https://github.com/bitwarden/server.git
synced 2025-07-02 16:42:50 -05:00
[AC-1218] Add ability to delete Provider Portals (#3973)
* add new classes * initial commit * revert the changes on this files Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * revert unnecessary changes * Add a model * add the delete token endpoint * add a unit test for delete provider Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * add the delete provider method Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * resolve the failing test Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * resolve the delete request redirect issue Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * changes to correct the json issue Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * resolve errors Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * resolve pr comment Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * move ProviderDeleteTokenable to the adminConsole Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * Add feature flag * resolve pr comments Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * add some unit test Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * resolve the failing test Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * resolve test Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * add the remove feature flag Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * [AC-2378] Added `ProviderId` to PayPal transaction model (#3995) * Added ProviderId to PayPal transaction model * Fixed issue with parsing provider id * [AC-1923] Add endpoint to create client organization (#3977) * Add new endpoint for creating client organizations in consolidated billing * Create empty org and then assign seats for code re-use * Fixes made from debugging client side * few more small fixes * Vincent's feedback * Bumped version to 2024.4.1 (#3997) * [AC-1923] Add endpoint to create client organization (#3977) * Add new endpoint for creating client organizations in consolidated billing * Create empty org and then assign seats for code re-use * Fixes made from debugging client side * few more small fixes * Vincent's feedback * [AC-1923] Add endpoint to create client organization (#3977) * Add new endpoint for creating client organizations in consolidated billing * Create empty org and then assign seats for code re-use * Fixes made from debugging client side * few more small fixes * Vincent's feedback * add changes after merge conflict Signed-off-by: Cy Okeke <cokeke@bitwarden.com> --------- Signed-off-by: Cy Okeke <cokeke@bitwarden.com> Co-authored-by: Conner Turnbull <133619638+cturnbull-bitwarden@users.noreply.github.com> Co-authored-by: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com> Co-authored-by: Bitwarden DevOps <106330231+bitwarden-devops-bot@users.noreply.github.com>
This commit is contained in:
@ -0,0 +1,37 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Business.Tokenables;
|
||||
|
||||
public class ProviderDeleteTokenable : Tokens.ExpiringTokenable
|
||||
{
|
||||
public const string ClearTextPrefix = "BwProviderId";
|
||||
public const string DataProtectorPurpose = "ProviderDeleteDataProtector";
|
||||
public const string TokenIdentifier = "ProviderDelete";
|
||||
public string Identifier { get; set; } = TokenIdentifier;
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[JsonConstructor]
|
||||
public ProviderDeleteTokenable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
public ProviderDeleteTokenable(DateTime expirationDate)
|
||||
{
|
||||
ExpirationDate = expirationDate;
|
||||
}
|
||||
|
||||
public ProviderDeleteTokenable(Entities.Provider.Provider provider, int hoursTillExpiration)
|
||||
{
|
||||
Id = provider.Id;
|
||||
ExpirationDate = DateTime.UtcNow.AddHours(hoursTillExpiration);
|
||||
}
|
||||
|
||||
public bool IsValid(Entities.Provider.Provider provider)
|
||||
{
|
||||
return Id == provider.Id;
|
||||
}
|
||||
|
||||
protected override bool TokenIsValid() => Identifier == TokenIdentifier && Id != default;
|
||||
}
|
@ -26,5 +26,8 @@ public interface IProviderService
|
||||
Task LogProviderAccessToOrganizationAsync(Guid organizationId);
|
||||
Task ResendProviderSetupInviteEmailAsync(Guid providerId, Guid ownerId);
|
||||
Task SendProviderSetupInviteEmailAsync(Provider provider, string ownerEmail);
|
||||
Task InitiateDeleteAsync(Provider provider, string providerAdminEmail);
|
||||
Task DeleteAsync(Provider provider, string token);
|
||||
Task DeleteAsync(Provider provider);
|
||||
}
|
||||
|
||||
|
@ -35,4 +35,7 @@ public class NoopProviderService : IProviderService
|
||||
|
||||
public Task ResendProviderSetupInviteEmailAsync(Guid providerId, Guid userId) => throw new NotImplementedException();
|
||||
public Task SendProviderSetupInviteEmailAsync(Provider provider, string ownerEmail) => throw new NotImplementedException();
|
||||
public Task InitiateDeleteAsync(Provider provider, string providerAdminEmail) => throw new NotImplementedException();
|
||||
public Task DeleteAsync(Provider provider, string token) => throw new NotImplementedException();
|
||||
public Task DeleteAsync(Provider provider) => throw new NotImplementedException();
|
||||
}
|
||||
|
@ -128,11 +128,12 @@ public static class FeatureFlagKeys
|
||||
public const string FlexibleCollectionsMigration = "flexible-collections-migration";
|
||||
public const string PM5766AutomaticTax = "PM-5766-automatic-tax";
|
||||
public const string PM5864DollarThreshold = "PM-5864-dollar-threshold";
|
||||
public const string AC2101UpdateTrialInitiationEmail = "AC-2101-update-trial-initiation-email";
|
||||
public const string ShowPaymentMethodWarningBanners = "show-payment-method-warning-banners";
|
||||
public const string AC2101UpdateTrialInitiationEmail = "AC-2101-update-trial-initiation-email";
|
||||
public const string EnableConsolidatedBilling = "enable-consolidated-billing";
|
||||
public const string AC1795_UpdatedSubscriptionStatusSection = "AC-1795_updated-subscription-status-section";
|
||||
public const string UnassignedItemsBanner = "unassigned-items-banner";
|
||||
public const string EnableDeleteProvider = "AC-1218-delete-provider";
|
||||
|
||||
public static List<string> GetAllKeys()
|
||||
{
|
||||
|
@ -3,5 +3,6 @@
|
||||
public enum ApplicationCacheMessageType : byte
|
||||
{
|
||||
UpsertOrganizationAbility = 0,
|
||||
DeleteOrganizationAbility = 1
|
||||
DeleteOrganizationAbility = 1,
|
||||
DeleteProviderAbility = 2,
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
{{#>FullHtmlLayout}}
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; box-sizing: border-box; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
|
||||
<tr style="margin: 0; box-sizing: border-box; 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 0 10px; -webkit-text-size-adjust: none; text-align: left;" valign="top" align="center">
|
||||
We recently received your request to permanently delete the following Bitwarden provider:
|
||||
</td>
|
||||
</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="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 0 10px; -webkit-text-size-adjust: none;" valign="top">
|
||||
<b 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;">Name:</b> {{ProviderName}}<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;" />
|
||||
<b 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;">ID:</b> {{ProviderId}}<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;" />
|
||||
<b 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;">Created:</b> {{ProviderCreationDate}} at {{ProviderCreationTime}} {{TimeZone}}<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;" />
|
||||
<b 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;">Billing email address:</b> {{ProviderBillingEmail}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="margin: 0; box-sizing: border-box; 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 0 10px; -webkit-text-size-adjust: none; text-align: left;" valign="top" align="center">
|
||||
Click the link below to delete your Bitwarden provider.
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="margin: 0; box-sizing: border-box; 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; text-align: left;" valign="top" align="center">
|
||||
If you did not request this email to delete your Bitwarden provider, you can safely ignore it.
|
||||
<br style="margin: 0; box-sizing: border-box; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;" />
|
||||
<br style="margin: 0; box-sizing: border-box; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="margin: 0; box-sizing: border-box; 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 0 10px; -webkit-text-size-adjust: none; text-align: center;" valign="top" align="center">
|
||||
<a href="{{{Url}}}" clicktracking=off target="_blank" 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;">
|
||||
Delete Your Provider
|
||||
</a>
|
||||
<br style="margin: 0; box-sizing: border-box; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{/FullHtmlLayout}}
|
@ -0,0 +1,15 @@
|
||||
{{#>BasicTextLayout}}
|
||||
We recently received your request to permanently delete the following Bitwarden provider:
|
||||
|
||||
- Name: {{ProviderName}}
|
||||
- ID: {{ProviderId}}
|
||||
- Created: {{ProviderCreationDate}} at {{ProviderCreationTime}} {{TimeZone}}
|
||||
- Billing email address: {{ProviderBillingEmail}}
|
||||
|
||||
Click the link below to complete the deletion of your provider.
|
||||
|
||||
If you did not request this email to delete your Bitwarden provider, you can safely ignore it.
|
||||
|
||||
{{{Url}}}
|
||||
|
||||
{{/BasicTextLayout}}
|
21
src/Core/Models/Mail/Provider/ProviderInitiateDeleteModel.cs
Normal file
21
src/Core/Models/Mail/Provider/ProviderInitiateDeleteModel.cs
Normal file
@ -0,0 +1,21 @@
|
||||
namespace Bit.Core.Models.Mail.Provider;
|
||||
|
||||
public class ProviderInitiateDeleteModel : BaseMailModel
|
||||
{
|
||||
public string Url => string.Format("{0}/verify-recover-delete-provider?providerId={1}&token={2}&name={3}",
|
||||
WebVaultUrl,
|
||||
ProviderId,
|
||||
Token,
|
||||
ProviderNameUrlEncoded);
|
||||
|
||||
public string WebVaultUrl { get; set; }
|
||||
public string Token { get; set; }
|
||||
public Guid ProviderId { get; set; }
|
||||
public string SiteName { get; set; }
|
||||
public string ProviderName { get; set; }
|
||||
public string ProviderNameUrlEncoded { get; set; }
|
||||
public string ProviderBillingEmail { get; set; }
|
||||
public string ProviderCreationDate { get; set; }
|
||||
public string ProviderCreationTime { get; set; }
|
||||
public string TimeZone { get; set; }
|
||||
}
|
@ -15,4 +15,5 @@ public interface IApplicationCacheService
|
||||
Task UpsertOrganizationAbilityAsync(Organization organization);
|
||||
Task UpsertProviderAbilityAsync(Provider provider);
|
||||
Task DeleteOrganizationAbilityAsync(Guid organizationId);
|
||||
Task DeleteProviderAbilityAsync(Guid providerId);
|
||||
}
|
||||
|
@ -78,5 +78,6 @@ public interface IMailService
|
||||
Task SendSecretsManagerMaxServiceAccountLimitReachedEmailAsync(Organization organization, int maxSeatCount, IEnumerable<string> ownerEmails);
|
||||
Task SendTrustedDeviceAdminApprovalEmailAsync(string email, DateTime utcNow, string ip, string deviceTypeAndIdentifier);
|
||||
Task SendTrialInitiationEmailAsync(string email);
|
||||
Task SendInitiateDeletProviderEmailAsync(string email, Provider provider, string token);
|
||||
}
|
||||
|
||||
|
@ -267,6 +267,28 @@ public class HandlebarsMailService : IMailService
|
||||
await _mailDeliveryService.SendEmailAsync(message);
|
||||
}
|
||||
|
||||
public async Task SendInitiateDeletProviderEmailAsync(string email, Provider provider, string token)
|
||||
{
|
||||
var message = CreateDefaultMessage("Request to Delete Your Provider", email);
|
||||
var model = new ProviderInitiateDeleteModel
|
||||
{
|
||||
Token = WebUtility.UrlEncode(token),
|
||||
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
|
||||
SiteName = _globalSettings.SiteName,
|
||||
ProviderId = provider.Id,
|
||||
ProviderName = CoreHelpers.SanitizeForEmail(provider.DisplayName(), false),
|
||||
ProviderNameUrlEncoded = WebUtility.UrlEncode(provider.Name),
|
||||
ProviderBillingEmail = provider.BillingEmail,
|
||||
ProviderCreationDate = provider.CreationDate.ToLongDateString(),
|
||||
ProviderCreationTime = provider.CreationDate.ToShortTimeString(),
|
||||
TimeZone = _utcTimeZoneDisplay,
|
||||
};
|
||||
await AddMessageContentAsync(message, "Provider.InitiateDeleteProvider", model);
|
||||
message.MetaData.Add("SendGridBypassListManagement", true);
|
||||
message.Category = "InitiateDeleteProvider";
|
||||
await _mailDeliveryService.SendEmailAsync(message);
|
||||
}
|
||||
|
||||
public async Task SendPasswordlessSignInAsync(string returnUrl, string token, string email)
|
||||
{
|
||||
var message = CreateDefaultMessage("[Admin] Continue Logging In", email);
|
||||
|
@ -85,6 +85,16 @@ public class InMemoryApplicationCacheService : IApplicationCacheService
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public virtual Task DeleteProviderAbilityAsync(Guid providerId)
|
||||
{
|
||||
if (_providerAbilities != null && _providerAbilities.ContainsKey(providerId))
|
||||
{
|
||||
_providerAbilities.Remove(providerId);
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task InitOrganizationAbilitiesAsync()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
@ -64,4 +64,19 @@ public class InMemoryServiceBusApplicationCacheService : InMemoryApplicationCach
|
||||
{
|
||||
await base.DeleteOrganizationAbilityAsync(organizationId);
|
||||
}
|
||||
|
||||
public override async Task DeleteProviderAbilityAsync(Guid providerId)
|
||||
{
|
||||
await base.DeleteProviderAbilityAsync(providerId);
|
||||
var message = new ServiceBusMessage
|
||||
{
|
||||
Subject = _subName,
|
||||
ApplicationProperties =
|
||||
{
|
||||
{ "type", (byte)ApplicationCacheMessageType.DeleteProviderAbility },
|
||||
{ "id", providerId },
|
||||
}
|
||||
};
|
||||
var task = _topicMessageSender.SendMessageAsync(message);
|
||||
}
|
||||
}
|
||||
|
@ -268,5 +268,7 @@ public class NoopMailService : IMailService
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SendInitiateDeletProviderEmailAsync(string email, Provider provider, string token) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user