diff --git a/src/Admin/Controllers/HomeController.cs b/src/Admin/Controllers/HomeController.cs index 20c1be70d0..9497be03aa 100644 --- a/src/Admin/Controllers/HomeController.cs +++ b/src/Admin/Controllers/HomeController.cs @@ -11,13 +11,17 @@ namespace Bit.Admin.Controllers; public class HomeController : Controller { private readonly GlobalSettings _globalSettings; - private readonly HttpClient _httpClient = new HttpClient(); + private readonly HttpClient _httpClient; private readonly ILogger _logger; - public HomeController(GlobalSettings globalSettings, ILogger logger) + public HomeController( + GlobalSettings globalSettings, + ILogger logger, + IHttpClientFactory httpClientFactory) { _globalSettings = globalSettings; _logger = logger; + _httpClient = httpClientFactory.CreateClient(); } [Authorize] diff --git a/src/Admin/Jobs/AliveJob.cs b/src/Admin/Jobs/AliveJob.cs index b97d597e58..2e8de43275 100644 --- a/src/Admin/Jobs/AliveJob.cs +++ b/src/Admin/Jobs/AliveJob.cs @@ -8,14 +8,16 @@ namespace Bit.Admin.Jobs; public class AliveJob : BaseJob { private readonly GlobalSettings _globalSettings; - private HttpClient _httpClient = new HttpClient(); + private readonly HttpClient _httpClient; public AliveJob( GlobalSettings globalSettings, - ILogger logger) + ILogger logger, + IHttpClientFactory httpClientFactory) : base(logger) { _globalSettings = globalSettings; + _httpClient = httpClientFactory.CreateClient(); } protected async override Task ExecuteJobAsync(IJobExecutionContext context) diff --git a/src/Api/Tools/Controllers/HibpController.cs b/src/Api/Tools/Controllers/HibpController.cs index f12027cb31..0d05b94e7e 100644 --- a/src/Api/Tools/Controllers/HibpController.cs +++ b/src/Api/Tools/Controllers/HibpController.cs @@ -16,27 +16,24 @@ public class HibpController : Controller { private const string HibpBreachApi = "https://haveibeenpwned.com/api/v3/breachedaccount/{0}" + "?truncateResponse=false&includeUnverified=false"; - private static HttpClient _httpClient; + private readonly HttpClient _httpClient; private readonly IUserService _userService; private readonly ICurrentContext _currentContext; private readonly GlobalSettings _globalSettings; private readonly string _userAgent; - static HibpController() - { - _httpClient = new HttpClient(); - } - public HibpController( IUserService userService, ICurrentContext currentContext, - GlobalSettings globalSettings) + GlobalSettings globalSettings, + IHttpClientFactory httpClientFactory) { _userService = userService; _currentContext = currentContext; _globalSettings = globalSettings; _userAgent = _globalSettings.SelfHosted ? "Bitwarden Self-Hosted" : "Bitwarden"; + _httpClient = httpClientFactory.CreateClient(); } [HttpGet("breach")] diff --git a/src/Billing/Controllers/FreshsalesController.cs b/src/Billing/Controllers/FreshsalesController.cs index 0182011d7a..d825a2d071 100644 --- a/src/Billing/Controllers/FreshsalesController.cs +++ b/src/Billing/Controllers/FreshsalesController.cs @@ -1,5 +1,4 @@ -using System.Net.Http.Headers; -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; using Bit.Core.Billing.Enums; using Bit.Core.Repositories; using Bit.Core.Settings; @@ -25,23 +24,16 @@ public class FreshsalesController : Controller IOrganizationRepository organizationRepository, IOptions billingSettings, ILogger logger, - GlobalSettings globalSettings) + GlobalSettings globalSettings, + IHttpClientFactory httpClientFactory) { _userRepository = userRepository; _organizationRepository = organizationRepository; _logger = logger; _globalSettings = globalSettings; - - _httpClient = new HttpClient - { - BaseAddress = new Uri("https://bitwarden.freshsales.io/api/") - }; + _httpClient = httpClientFactory.CreateClient("Freshsales"); _freshsalesApiKey = billingSettings.Value.FreshsalesApiKey; - - _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - "Token", - $"token={_freshsalesApiKey}"); } diff --git a/src/Billing/Startup.cs b/src/Billing/Startup.cs index 89ac840b14..e6b2ac03e9 100644 --- a/src/Billing/Startup.cs +++ b/src/Billing/Startup.cs @@ -10,6 +10,7 @@ using Bit.Core.Settings; using Bit.Core.Utilities; using Bit.SharedWeb.Utilities; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; using Quartz; using Stripe; @@ -102,6 +103,15 @@ public class Startup { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", billingSettings.Onyx.ApiKey); }); + services.AddHttpClient("Freshsales", (sp, client) => + { + var billingSettings = sp.GetRequiredService>().Value; + client.BaseAddress = new Uri("https://bitwarden.freshsales.io/api/"); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( + "Token", + $"token={billingSettings.FreshsalesApiKey}" + ); + }); services.AddScoped(); services.AddScoped(); diff --git a/test/Billing.Test/Controllers/FreshsalesControllerTests.cs b/test/Billing.Test/Controllers/FreshsalesControllerTests.cs index c9ae6efb1a..c9eb8c8e40 100644 --- a/test/Billing.Test/Controllers/FreshsalesControllerTests.cs +++ b/test/Billing.Test/Controllers/FreshsalesControllerTests.cs @@ -31,12 +31,18 @@ public class FreshsalesControllerTests var globalSettings = new GlobalSettings(); globalSettings.BaseServiceUri.Admin = "https://test.com"; + var httpClientFactory = Substitute.For(); + httpClientFactory + .CreateClient("Freshsales") + .Returns(new HttpClient()); + var sut = new FreshsalesController( userRepository, organizationRepository, billingSettings, Substitute.For>(), - globalSettings + globalSettings, + httpClientFactory ); return (sut, userRepository, organizationRepository); diff --git a/util/Setup/Program.cs b/util/Setup/Program.cs index 50f3046d6d..bb857a3276 100644 --- a/util/Setup/Program.cs +++ b/util/Setup/Program.cs @@ -2,6 +2,7 @@ using System.Net.Http.Json; using Bit.Migrator; using Bit.Setup.Enums; +using Microsoft.Extensions.DependencyInjection; namespace Bit.Setup; @@ -285,7 +286,14 @@ public class Program url = $"{installationUrl}/installations/"; } - var response = new HttpClient().GetAsync(url + _context.Install.InstallationId).GetAwaiter().GetResult(); + // We need to get an HttpClient that has been configured with custom trust certificates. + var httpClient = new ServiceCollection() + .AddX509ChainCustomization() + .BuildServiceProvider() + .GetRequiredService() + .CreateClient(); + + var response = httpClient.GetAsync(url + _context.Install.InstallationId).GetAwaiter().GetResult(); if (!response.IsSuccessStatusCode) {