diff --git a/bff/hosts/Hosts.Bff.EF/Extensions.cs b/bff/hosts/Hosts.Bff.EF/Extensions.cs index 43152e913..449af16d0 100644 --- a/bff/hosts/Hosts.Bff.EF/Extensions.cs +++ b/bff/hosts/Hosts.Bff.EF/Extensions.cs @@ -1,3 +1,4 @@ +using System; using Duende.Bff; using Duende.Bff.Yarp; using Microsoft.AspNetCore.Builder; @@ -46,7 +47,7 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde { // host prefixed cookie name options.Cookie.Name = "__Host-spa-ef"; - + options.ExpireTimeSpan = TimeSpan.FromMinutes(5); // strict SameSite handling options.Cookie.SameSite = SameSiteMode.Strict; }) diff --git a/bff/hosts/Hosts.Bff.InMemory/Extensions.cs b/bff/hosts/Hosts.Bff.InMemory/Extensions.cs index 5ec23faf1..e075367b0 100644 --- a/bff/hosts/Hosts.Bff.InMemory/Extensions.cs +++ b/bff/hosts/Hosts.Bff.InMemory/Extensions.cs @@ -42,7 +42,7 @@ Func getServiceProvider .AddCookie("cookie", options => { // set session lifetime - options.ExpireTimeSpan = TimeSpan.FromHours(8); + options.ExpireTimeSpan = TimeSpan.FromMinutes(8); // sliding or absolute options.SlidingExpiration = false; diff --git a/bff/hosts/Hosts.IdentityServer/ServiceDiscoveringClientStore.cs b/bff/hosts/Hosts.IdentityServer/ServiceDiscoveringClientStore.cs index 22035d977..5e83e5839 100644 --- a/bff/hosts/Hosts.IdentityServer/ServiceDiscoveringClientStore.cs +++ b/bff/hosts/Hosts.IdentityServer/ServiceDiscoveringClientStore.cs @@ -59,7 +59,9 @@ private async Task Initialize() AllowOfflineAccess = true, AllowedScopes = { "openid", "profile", "api", "scope-for-isolated-api" }, - AccessTokenLifetime = 75 // Force refresh + RefreshTokenExpiration = TokenExpiration.Absolute, + AbsoluteRefreshTokenLifetime = 60, + AccessTokenLifetime = 15 // Force refresh }, new Client { @@ -101,8 +103,9 @@ private async Task Initialize() AllowOfflineAccess = true, AllowedScopes = { "openid", "profile", "api", "scope-for-isolated-api" }, - - AccessTokenLifetime = 75 // Force refresh + RefreshTokenExpiration = TokenExpiration.Absolute, + AbsoluteRefreshTokenLifetime = 60, + AccessTokenLifetime = 15 // Force refresh }, new Client diff --git a/bff/src/Bff/Configuration/BffOptions.cs b/bff/src/Bff/Configuration/BffOptions.cs index 8e8e801c9..9000ff2f6 100644 --- a/bff/src/Bff/Configuration/BffOptions.cs +++ b/bff/src/Bff/Configuration/BffOptions.cs @@ -106,7 +106,7 @@ public class BffOptions /// Interval at which expired sessions are cleaned up. /// Defaults to 10 minutes. /// - public TimeSpan SessionCleanupInterval { get; set; } = TimeSpan.FromMinutes(10); + public TimeSpan SessionCleanupInterval { get; set; } = TimeSpan.FromSeconds(10); ///// ///// Batch size expired sessions are deleted. diff --git a/bff/src/Bff/EndpointProcessing/BffMiddleware.cs b/bff/src/Bff/EndpointProcessing/BffMiddleware.cs index 481d78332..855eb3b62 100644 --- a/bff/src/Bff/EndpointProcessing/BffMiddleware.cs +++ b/bff/src/Bff/EndpointProcessing/BffMiddleware.cs @@ -2,8 +2,11 @@ // See LICENSE in the project root for license information. using System.Threading.Tasks; +using Duende.AccessTokenManagement.OpenIdConnect; using Duende.Bff.Logging; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -18,6 +21,7 @@ public class BffMiddleware private readonly RequestDelegate _next; private readonly BffOptions _options; private readonly ILogger _logger; + private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider; /// /// ctor @@ -25,11 +29,13 @@ public class BffMiddleware /// /// /// - public BffMiddleware(RequestDelegate next, IOptions options, ILogger logger) + /// + public BffMiddleware(RequestDelegate next, IOptions options, ILogger logger, IAuthenticationSchemeProvider authenticationSchemeProvider) { _next = next; _options = options.Value; _logger = logger; + _authenticationSchemeProvider = authenticationSchemeProvider; } /// @@ -42,8 +48,6 @@ public async Task Invoke(HttpContext context) // add marker so we can determine if middleware has run later in the pipeline context.Items[Constants.BffMiddlewareMarker] = true; - // inbound: add CSRF check for local APIs - var endpoint = context.GetEndpoint(); if (endpoint == null) { @@ -54,6 +58,42 @@ public async Task Invoke(HttpContext context) var isBffEndpoint = endpoint.Metadata.GetMetadata() != null; if (isBffEndpoint) { + if (context.User.Identity?.IsAuthenticated == true) + { + var userTokens = context.RequestServices.GetRequiredService(); + var token = await userTokens.GetTokenAsync(context.User); + + if (token.Expiration < DateTimeOffset.Now) + { + _logger.LogInformation("expired"); + + var tokenService = context.RequestServices.GetRequiredService(); + + token = await tokenService.GetAccessTokenAsync(context.User); + + if (token.Expiration < DateTimeOffset.Now) + { + // get rid of local cookie first + var signInScheme = await _authenticationSchemeProvider.GetDefaultSignInSchemeAsync(); + await context.SignOutAsync(signInScheme?.Name); + + var props = new AuthenticationProperties + { + RedirectUri = "/" + }; + + + // trigger idp logout + await context.SignOutAsync(props); + //context.RequestServices.GetRequiredService().DeleteUserSessionAsync() + context.Response.StatusCode = 401; + return; + } + + } + } + + var requireAntiForgeryCheck = endpoint.Metadata.GetMetadata() == null; if (requireAntiForgeryCheck) {