diff --git a/bitwarden_license/src/Sso/Startup.cs b/bitwarden_license/src/Sso/Startup.cs index f6be418bd8..5ed613e159 100644 --- a/bitwarden_license/src/Sso/Startup.cs +++ b/bitwarden_license/src/Sso/Startup.cs @@ -65,7 +65,7 @@ public class Startup } // Authentication - services.AddDistributedIdentityServices(globalSettings); + services.AddDistributedIdentityServices(); services.AddAuthentication() .AddCookie(AuthenticationSchemes.BitwardenExternalCookieAuthenticationScheme); services.AddSsoServices(globalSettings); diff --git a/src/Core/IdentityServer/ConfigureOpenIdConnectDistributedOptions.cs b/src/Core/IdentityServer/ConfigureOpenIdConnectDistributedOptions.cs index 476159b760..cbb91a1e72 100644 --- a/src/Core/IdentityServer/ConfigureOpenIdConnectDistributedOptions.cs +++ b/src/Core/IdentityServer/ConfigureOpenIdConnectDistributedOptions.cs @@ -1,8 +1,8 @@ -using Bit.Core.Settings; -using Duende.IdentityServer.Configuration; +using Duende.IdentityServer.Configuration; using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Caching.StackExchangeRedis; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace Bit.Core.IdentityServer; @@ -10,15 +10,18 @@ namespace Bit.Core.IdentityServer; public class ConfigureOpenIdConnectDistributedOptions : IPostConfigureOptions { private readonly IdentityServerOptions _idsrv; - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly GlobalSettings _globalSettings; + private readonly IDistributedCache _distributedCache; + private readonly IDataProtectionProvider _dataProtectionProvider; - public ConfigureOpenIdConnectDistributedOptions(IHttpContextAccessor httpContextAccessor, GlobalSettings globalSettings, + public ConfigureOpenIdConnectDistributedOptions( + [FromKeyedServices("persistent")] + IDistributedCache distributedCache, + IDataProtectionProvider dataProtectionProvider, IdentityServerOptions idsrv) { - _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); - _globalSettings = globalSettings; _idsrv = idsrv; + _distributedCache = distributedCache; + _dataProtectionProvider = dataProtectionProvider; } public void PostConfigure(string name, CookieAuthenticationOptions options) @@ -34,19 +37,7 @@ public class ConfigureOpenIdConnectDistributedOptions : IPostConfigureOptions - context.RequestServices.GetRequiredService(); + context.RequestServices.GetRequiredKeyedService("persistent"); private string GetKey(string key, string id) => $"{CacheKeyPrefix}-{key}-{id}"; diff --git a/src/Core/IdentityServer/DistributedCacheTicketDataFormatter.cs b/src/Core/IdentityServer/DistributedCacheTicketDataFormatter.cs index ec47a0f7c0..6a4b7439d4 100644 --- a/src/Core/IdentityServer/DistributedCacheTicketDataFormatter.cs +++ b/src/Core/IdentityServer/DistributedCacheTicketDataFormatter.cs @@ -1,32 +1,32 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.DependencyInjection; namespace Bit.Core.IdentityServer; public class DistributedCacheTicketDataFormatter : ISecureDataFormat { - private readonly IHttpContextAccessor _httpContext; - private readonly string _name; + private const string CacheKeyPrefix = "ticket-data"; - public DistributedCacheTicketDataFormatter(IHttpContextAccessor httpContext, string name) + private readonly IDistributedCache _distributedCache; + private readonly IDataProtector _dataProtector; + private readonly string _prefix; + + public DistributedCacheTicketDataFormatter( + IDistributedCache distributedCache, + IDataProtectionProvider dataProtectionProvider, + string name) { - _httpContext = httpContext; - _name = name; + _distributedCache = distributedCache; + _dataProtector = dataProtectionProvider.CreateProtector(CacheKeyPrefix, name); + _prefix = $"{CacheKeyPrefix}-{name}"; } - private string CacheKeyPrefix => "ticket-data"; - private IDistributedCache Cache => _httpContext.HttpContext.RequestServices.GetRequiredService(); - private IDataProtector Protector => _httpContext.HttpContext.RequestServices.GetRequiredService() - .CreateProtector(CacheKeyPrefix, _name); - public string Protect(AuthenticationTicket data) => Protect(data, null); public string Protect(AuthenticationTicket data, string purpose) { var key = Guid.NewGuid().ToString(); - var cacheKey = $"{CacheKeyPrefix}-{_name}-{purpose}-{key}"; + var cacheKey = $"{_prefix}-{purpose}-{key}"; var expiresUtc = data.Properties.ExpiresUtc ?? DateTimeOffset.UtcNow.AddMinutes(15); @@ -35,9 +35,9 @@ public class DistributedCacheTicketDataFormatter : ISecureDataFormat Unprotect(protectedText, null); @@ -49,9 +49,9 @@ public class DistributedCacheTicketDataFormatter : ISecureDataFormat StoreAsync(AuthenticationTicket ticket) { - var key = $"{_keyPrefix}{Guid.NewGuid()}"; + var key = $"{KeyPrefix}{Guid.NewGuid()}"; await RenewAsync(key, ticket); return key; diff --git a/src/Core/IdentityServer/MemoryCacheTicketStore.cs b/src/Core/IdentityServer/MemoryCacheTicketStore.cs deleted file mode 100644 index dc8d763c9c..0000000000 --- a/src/Core/IdentityServer/MemoryCacheTicketStore.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.Extensions.Caching.Memory; - -namespace Bit.Core.IdentityServer; - -public class MemoryCacheTicketStore : ITicketStore -{ - private const string _keyPrefix = "auth-"; - private readonly IMemoryCache _cache; - - public MemoryCacheTicketStore() - { - _cache = new MemoryCache(new MemoryCacheOptions()); - } - - public async Task StoreAsync(AuthenticationTicket ticket) - { - var key = $"{_keyPrefix}{Guid.NewGuid()}"; - await RenewAsync(key, ticket); - return key; - } - - public Task RenewAsync(string key, AuthenticationTicket ticket) - { - var options = new MemoryCacheEntryOptions(); - var expiresUtc = ticket.Properties.ExpiresUtc; - if (expiresUtc.HasValue) - { - options.SetAbsoluteExpiration(expiresUtc.Value); - } - else - { - options.SetSlidingExpiration(TimeSpan.FromMinutes(15)); - } - - _cache.Set(key, ticket, options); - - return Task.FromResult(0); - } - - public Task RetrieveAsync(string key) - { - _cache.TryGetValue(key, out AuthenticationTicket ticket); - return Task.FromResult(ticket); - } - - public Task RemoveAsync(string key) - { - _cache.Remove(key); - return Task.FromResult(0); - } -} diff --git a/src/Identity/IdentityServer/CustomTokenRequestValidator.cs b/src/Identity/IdentityServer/CustomTokenRequestValidator.cs index 96243533ed..fbd522c814 100644 --- a/src/Identity/IdentityServer/CustomTokenRequestValidator.cs +++ b/src/Identity/IdentityServer/CustomTokenRequestValidator.cs @@ -46,6 +46,7 @@ public class CustomTokenRequestValidator : BaseRequestValidator tokenDataFactory, IFeatureService featureService, + [FromKeyedServices("persistent")] IDistributedCache distributedCache, IUserDecryptionOptionsBuilder userDecryptionOptionsBuilder) : base(userManager, deviceRepository, deviceService, userService, eventService, diff --git a/src/Identity/IdentityServer/ResourceOwnerPasswordValidator.cs b/src/Identity/IdentityServer/ResourceOwnerPasswordValidator.cs index 84d047fa28..4ca31e8bf3 100644 --- a/src/Identity/IdentityServer/ResourceOwnerPasswordValidator.cs +++ b/src/Identity/IdentityServer/ResourceOwnerPasswordValidator.cs @@ -49,6 +49,7 @@ public class ResourceOwnerPasswordValidator : BaseRequestValidator tokenDataFactory, IFeatureService featureService, ISsoConfigRepository ssoConfigRepository, + [FromKeyedServices("persistent")] IDistributedCache distributedCache, IUserDecryptionOptionsBuilder userDecryptionOptionsBuilder) : base(userManager, deviceRepository, deviceService, userService, eventService, diff --git a/src/Identity/IdentityServer/WebAuthnGrantValidator.cs b/src/Identity/IdentityServer/WebAuthnGrantValidator.cs index 0f9c85f020..c9a4ee4ade 100644 --- a/src/Identity/IdentityServer/WebAuthnGrantValidator.cs +++ b/src/Identity/IdentityServer/WebAuthnGrantValidator.cs @@ -50,6 +50,7 @@ public class WebAuthnGrantValidator : BaseRequestValidator tokenDataFactory, IDataProtectorTokenFactory assertionOptionsDataProtector, IFeatureService featureService, + [FromKeyedServices("persistent")] IDistributedCache distributedCache, IUserDecryptionOptionsBuilder userDecryptionOptionsBuilder, IAssertWebAuthnLoginCredentialCommand assertWebAuthnLoginCredentialCommand diff --git a/src/Identity/Startup.cs b/src/Identity/Startup.cs index 7f699e70a7..dd6ba42bd0 100644 --- a/src/Identity/Startup.cs +++ b/src/Identity/Startup.cs @@ -91,7 +91,7 @@ public class Startup // Authentication services - .AddDistributedIdentityServices(globalSettings) + .AddDistributedIdentityServices() .AddAuthentication() .AddCookie(AuthenticationSchemes.BitwardenExternalCookieAuthenticationScheme) .AddOpenIdConnect("sso", "Single Sign On", options => diff --git a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs index 8c07fadf90..1bd805fb8e 100644 --- a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs +++ b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs @@ -35,7 +35,6 @@ using Bit.Core.Vault.Services; using Bit.Infrastructure.Dapper; using Bit.Infrastructure.EntityFramework; using DnsClient; -using Duende.IdentityServer.Configuration; using IdentityModel; using LaunchDarkly.Sdk.Server; using LaunchDarkly.Sdk.Server.Interfaces; @@ -632,18 +631,13 @@ public static class ServiceCollectionExtensions }); } - public static IServiceCollection AddDistributedIdentityServices(this IServiceCollection services, GlobalSettings globalSettings) + public static IServiceCollection AddDistributedIdentityServices(this IServiceCollection services) { services.AddOidcStateDataFormatterCache(); services.AddSession(); services.ConfigureApplicationCookie(configure => configure.CookieManager = new DistributedCacheCookieManager()); services.ConfigureExternalCookie(configure => configure.CookieManager = new DistributedCacheCookieManager()); - services.AddSingleton>( - svcs => new ConfigureOpenIdConnectDistributedOptions( - svcs.GetRequiredService(), - globalSettings, - svcs.GetRequiredService()) - ); + services.AddSingleton, ConfigureOpenIdConnectDistributedOptions>(); return services; }