1
0
mirror of https://github.com/bitwarden/server synced 2026-01-03 17:14:00 +00:00

[AC-1637] Sanitize Business and Organization Names from html script injection prior to storing in db (#3302)

* [AC-1637] Added HtmlEncodingStringConverter to encode/decode special chars on JSON serialization/deserialization

* [AC-1637] Added unit tests for HtmlEncodingStringConverter

* [AC-1637] Moved expected values on unit tests to the arrange phase

* [AC-1637] Added HtmlEncodingStringConverter to properties that are for input/output of Org Name and Business name

* [AC-1637] Modified views in Admin project to decode values to display

* [AC-1637] Replaced Html.Raw with HttpUtility.HtmlDecode

* [AC-1637] Added JsonConverter to Provider DTOs

* [AC-1637] Modified HandlebarsMailService to decode organization name before sending emails

* Revert "[AC-1637] Added JsonConverter to Provider DTOs"

This reverts commit 94d507cf93.

* [AC-1637] Fixed Admin panel organization search

* [AC-1637] Sanitizing Organization name and business name on creation in Admin panel

* [AC-1637] Sanitizing organization name and business name on creation by a provider

* [AC-1637] Sanitizing provider name on creation and on viewing in admin panel

* [AC-1637] Added sanitization to more places where Org name is used

* [AC-1637] Swapped using HttpUtility for WebUtility since the later is part of the dotnet framework

* [AC-1637] Updated error messages

* [AC-1637] Decoding on Admin panel add existing organization

* [AC-1637] Fix HTML decoding issues

* [AC-1637] Refactor HTML decoding in View and Model classes on Admin panel

* [AC-1637] Refactor provider name and business name usages to use methods that output decoded values

* [AC-1637] Fixed typo

* [AC-1637] Renamed Provider methods to retrieve Decoded Name and BusinessName

* [AC-1637] Renamed Organization methods to retrieve Decoded Name and BusinessName

* [AC-1637] Update the display name method in the `ProviderOrganizationOrganizationDetails` class to `DisplayName()`
This commit is contained in:
Rui Tomé
2024-03-05 10:56:48 +00:00
committed by GitHub
parent 997af0f6ab
commit 9d59e4dc9e
49 changed files with 312 additions and 79 deletions

View File

@@ -1,4 +1,5 @@
using Bit.Admin.AdminConsole.Models;
using System.Net;
using Bit.Admin.AdminConsole.Models;
using Bit.Admin.Enums;
using Bit.Admin.Services;
using Bit.Admin.Utilities;
@@ -119,8 +120,9 @@ public class OrganizationsController : Controller
count = 1;
}
var encodedName = WebUtility.HtmlEncode(name);
var skip = (page - 1) * count;
var organizations = await _organizationRepository.SearchAsync(name, userEmail, paid, skip, count);
var organizations = await _organizationRepository.SearchAsync(encodedName, userEmail, paid, skip, count);
return View(new OrganizationsModel
{
Items = organizations as List<Organization>,

View File

@@ -1,4 +1,5 @@
using Bit.Admin.AdminConsole.Models;
using System.Net;
using Bit.Admin.AdminConsole.Models;
using Bit.Admin.Enums;
using Bit.Admin.Utilities;
using Bit.Core;
@@ -188,8 +189,9 @@ public class ProvidersController : Controller
count = 1;
}
var encodedName = WebUtility.HtmlEncode(name);
var skip = (page - 1) * count;
var unassignedOrganizations = await _organizationRepository.SearchUnassignedToProviderAsync(name, ownerEmail, skip, count);
var unassignedOrganizations = await _organizationRepository.SearchUnassignedToProviderAsync(encodedName, ownerEmail, skip, count);
var viewModel = new OrganizationUnassignedToProviderSearchViewModel
{
OrganizationName = string.IsNullOrWhiteSpace(name) ? null : name,
@@ -199,7 +201,7 @@ public class ProvidersController : Controller
Items = unassignedOrganizations.Select(uo => new OrganizationSelectableViewModel
{
Id = uo.Id,
Name = uo.Name,
Name = uo.DisplayName(),
PlanType = uo.PlanType
}).ToList()
};

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.Net;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Enums.Provider;
@@ -36,8 +37,8 @@ public class OrganizationEditModel : OrganizationViewModel
BillingInfo = billingInfo;
BraintreeMerchantId = globalSettings.Braintree.MerchantId;
Name = org.Name;
BusinessName = org.BusinessName;
Name = org.DisplayName();
BusinessName = org.DisplayBusinessName();
BillingEmail = provider?.Type == ProviderType.Reseller ? provider.BillingEmail : org.BillingEmail;
PlanType = org.PlanType;
Plan = org.Plan;
@@ -184,8 +185,8 @@ public class OrganizationEditModel : OrganizationViewModel
public Organization ToOrganization(Organization existingOrganization)
{
existingOrganization.Name = Name;
existingOrganization.BusinessName = BusinessName;
existingOrganization.Name = WebUtility.HtmlEncode(Name.Trim());
existingOrganization.BusinessName = WebUtility.HtmlEncode(BusinessName.Trim());
existingOrganization.BillingEmail = BillingEmail?.ToLowerInvariant()?.Trim();
existingOrganization.PlanType = PlanType.Value;
existingOrganization.Plan = Plan;

View File

@@ -11,8 +11,8 @@ public class ProviderEditModel : ProviderViewModel
public ProviderEditModel(Provider provider, IEnumerable<ProviderUserUserDetails> providerUsers, IEnumerable<ProviderOrganizationOrganizationDetails> organizations)
: base(provider, providerUsers, organizations)
{
Name = provider.Name;
BusinessName = provider.BusinessName;
Name = provider.DisplayName();
BusinessName = provider.DisplayBusinessName();
BillingEmail = provider.BillingEmail;
BillingPhone = provider.BillingPhone;
}

View File

@@ -4,7 +4,7 @@
@inject Bit.Admin.Services.IAccessControlService AccessControlService
@model OrganizationEditModel
@{
ViewData["Title"] = (Model.Provider != null ? "Client " : string.Empty) + "Organization: " + Model.Organization.Name;
ViewData["Title"] = (Model.Provider != null ? "Client " : string.Empty) + "Organization: " + Model.Name;
var canViewOrganizationInformation = AccessControlService.UserHasPermission(Permission.Org_OrgInformation_View);
var canViewBillingInformation = AccessControlService.UserHasPermission(Permission.Org_BillingInformation_View);
@@ -58,7 +58,7 @@
</script>
}
<h1>@(Model.Provider != null ? "Client " : string.Empty)Organization <small>@Model.Organization.Name</small></h1>
<h1>@(Model.Provider != null ? "Client " : string.Empty)Organization <small>@Model.Name</small></h1>
@if (Model.Provider != null)
{

View File

@@ -46,7 +46,7 @@
{
<tr>
<td>
<a asp-action="@Model.Action" asp-route-id="@org.Id">@org.Name</a>
<a asp-action="@Model.Action" asp-route-id="@org.Id">@org.DisplayName()</a>
</td>
<td>
@org.Plan

View File

@@ -1,10 +1,10 @@
@inject Bit.Core.Settings.GlobalSettings GlobalSettings
@model OrganizationViewModel
@{
ViewData["Title"] = "Organization: " + Model.Organization.Name;
ViewData["Title"] = "Organization: " + Model.Organization.DisplayName();
}
<h1>Organization <small>@Model.Organization.Name</small></h1>
<h1>Organization <small>@Model.Organization.DisplayName()</small></h1>
@if (Model.Provider != null)
{

View File

@@ -2,8 +2,8 @@
@model Bit.Core.AdminConsole.Entities.Provider.Provider
<dl class="row">
<dt class="col-sm-4 col-lg-3">Provider Name</dt>
<dd class="col-sm-8 col-lg-9">@Model.Name</dd>
<dd class="col-sm-8 col-lg-9">@Model.DisplayName()</dd>
<dt class="col-sm-4 col-lg-3">Provider Type</dt>
<dd class="col-sm-8 col-lg-9">@(Model.Type.GetDisplayAttribute()?.GetName())</dd>
</dl>
</dl>

View File

@@ -45,7 +45,7 @@
@Html.HiddenFor(m => Model.Items[i].Id, new { @readonly = "readonly", autocomplete = "off" })
@Html.CheckBoxFor(m => Model.Items[i].Selected)
</td>
<td>@Html.ActionLink(Model.Items[i].Name, "Edit", "Organizations", new { id = Model.Items[i].Id }, new { target = "_blank" })</td>
<td>@Html.ActionLink(Model.Items[i].DisplayName(), "Edit", "Organizations", new { id = Model.Items[i].Id }, new { target = "_blank" })</td>
<td>@(Model.Items[i].PlanType.GetDisplayAttribute()?.Name ?? Model.Items[i].PlanType.ToString())</td>
</tr>
}

View File

@@ -3,12 +3,12 @@
@model ProviderEditModel
@{
ViewData["Title"] = "Provider: " + Model.Provider.Name;
ViewData["Title"] = "Provider: " + Model.Provider.DisplayName();
var canEdit = AccessControlService.UserHasPermission(Permission.Provider_Edit);
}
<h1>Provider <small>@Model.Provider.Name</small></h1>
<h1>Provider <small>@Model.Provider.DisplayName()</small></h1>
<h2>Provider Information</h2>
@await Html.PartialAsync("_ViewInformation", Model)
@@ -17,12 +17,12 @@
<h2>General</h2>
<dl class="row">
<dt class="col-sm-4 col-lg-3">Name</dt>
<dd class="col-sm-8 col-lg-9">@Model.Provider.Name</dd>
<dd class="col-sm-8 col-lg-9">@Model.Provider.DisplayName()</dd>
</dl>
<h2>Business Information</h2>
<dl class="row">
<dt class="col-sm-4 col-lg-3">Business Name</dt>
<dd class="col-sm-8 col-lg-9">@Model.Provider.BusinessName</dd>
<dd class="col-sm-8 col-lg-9">@Model.Provider.DisplayBusinessName()</dd>
</dl>
<h2>Billing</h2>
<div class="row">

View File

@@ -52,7 +52,7 @@
{
<tr>
<td>
<a asp-action="@Model.Action" asp-route-id="@provider.Id">@(provider.Name ?? "Pending")</a>
<a asp-action="@Model.Action" asp-route-id="@provider.Id">@(!string.IsNullOrEmpty(provider.DisplayName()) ? provider.DisplayName() : "Pending")</a>
</td>
<td>@provider.Type.GetDisplayAttribute()?.GetShortName()</td>
<td>@provider.Status</td>

View File

@@ -45,7 +45,7 @@
{
<tr>
<td class="align-middle">
<a asp-controller="Organizations" asp-action="Edit" asp-route-id="@providerOrganization.OrganizationId">@providerOrganization.OrganizationName</a>
<a asp-controller="Organizations" asp-action="Edit" asp-route-id="@providerOrganization.OrganizationId">@providerOrganization.DisplayName()</a>
</td>
<td>
@providerOrganization.Status

View File

@@ -1,9 +1,9 @@
@model ProviderViewModel
@{
ViewData["Title"] = "Provider: " + Model.Provider.Name;
ViewData["Title"] = "Provider: " + Model.Provider.DisplayName();
}
<h1>Provider <small>@Model.Provider.Name</small></h1>
<h1>Provider <small>@Model.Provider.DisplayName()</small></h1>
<h2>Information</h2>
@await Html.PartialAsync("_ViewInformation", Model)

View File

@@ -28,7 +28,7 @@
<div class="col-sm">
<div class="form-group">
<label asp-for="Name"></label>
<input type="text" class="form-control" asp-for="Name" required>
<input type="text" class="form-control" asp-for="Name" value="@Model.Name" required>
</div>
</div>
</div>
@@ -68,7 +68,7 @@
<div class="col-sm">
<div class="form-group">
<label asp-for="BusinessName"></label>
<input type="text" class="form-control" asp-for="BusinessName">
<input type="text" class="form-control" asp-for="BusinessName" value="@Model.BusinessName">
</div>
</div>
</div>