From 68233951cb571bc110781fcbc629e976cef2c397 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 29 Sep 2025 09:39:15 -0400 Subject: [PATCH] implement single logout for OIDC --- Oqtane.Client/Modules/Admin/Users/Index.razor | 12 +++++++ .../Resources/Modules/Admin/Users/Index.resx | 6 ++++ Oqtane.Server/Pages/Logout.cshtml.cs | 31 +++++++++++++++---- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Users/Index.razor b/Oqtane.Client/Modules/Admin/Users/Index.razor index 0e76dc49..5e568a4a 100644 --- a/Oqtane.Client/Modules/Admin/Users/Index.razor +++ b/Oqtane.Client/Modules/Admin/Users/Index.razor @@ -329,6 +329,15 @@ else +
+ +
+ +
+
}
@@ -560,6 +569,7 @@ else private string _toggleclientsecret = string.Empty; private string _authresponsetype; private string _requirenonce; + private string _singlelogout; private string _scopes; private string _parameters; private string _pkce; @@ -648,6 +658,7 @@ else _toggleclientsecret = SharedLocalizer["ShowPassword"]; _authresponsetype = SettingService.GetSetting(settings, "ExternalLogin:AuthResponseType", "code"); _requirenonce = SettingService.GetSetting(settings, "ExternalLogin:RequireNonce", "true"); + _singlelogout = SettingService.GetSetting(settings, "ExternalLogin:SingleLogout", "false"); _scopes = SettingService.GetSetting(settings, "ExternalLogin:Scopes", ""); _parameters = SettingService.GetSetting(settings, "ExternalLogin:Parameters", ""); _pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false"); @@ -771,6 +782,7 @@ else settings = SettingService.SetSetting(settings, "ExternalLogin:ClientSecret", _clientsecret, true); settings = SettingService.SetSetting(settings, "ExternalLogin:AuthResponseType", _authresponsetype, true); settings = SettingService.SetSetting(settings, "ExternalLogin:RequireNonce", _requirenonce, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:SingleLogout", _singlelogout, true); settings = SettingService.SetSetting(settings, "ExternalLogin:Scopes", _scopes, true); settings = SettingService.SetSetting(settings, "ExternalLogin:Parameters", _parameters, true); settings = SettingService.SetSetting(settings, "ExternalLogin:PKCE", _pkce, true); diff --git a/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx index e9bc7d13..310e6dc3 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx @@ -555,4 +555,10 @@ If you would like to share cookies across subdomains you will need to specify a root domain with a leading dot (ie. '.example.com') + + Allow Single Logout? + + + Specify if users should be logged out of both the application and provider (the default is false indicating they will only be logged out of the application) + \ No newline at end of file diff --git a/Oqtane.Server/Pages/Logout.cshtml.cs b/Oqtane.Server/Pages/Logout.cshtml.cs index 72329c11..3d72d2ec 100644 --- a/Oqtane.Server/Pages/Logout.cshtml.cs +++ b/Oqtane.Server/Pages/Logout.cshtml.cs @@ -1,5 +1,8 @@ +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; @@ -8,6 +11,7 @@ using Oqtane.Extensions; using Oqtane.Infrastructure; using Oqtane.Managers; using Oqtane.Shared; +using Radzen.Blazor.Markdown; namespace Oqtane.Pages { @@ -28,6 +32,9 @@ namespace Oqtane.Pages public async Task OnPostAsync(string returnurl, string everywhere) { + returnurl = (returnurl == null) ? "/" : returnurl; + returnurl = (!returnurl.StartsWith("/")) ? "/" + returnurl : returnurl; + if (HttpContext.User != null) { var alias = HttpContext.GetAlias(); @@ -43,13 +50,25 @@ namespace Oqtane.Pages _logger.Log(LogLevel.Information, this, LogFunction.Security, "User Logout For Username {Username}", user.Username); } - await HttpContext.SignOutAsync(Constants.AuthenticationScheme); + var authenticationProperties = new AuthenticationProperties + { + RedirectUri = returnurl + }; + + var authenticationSchemes = new List(); + authenticationSchemes.Add(Constants.AuthenticationScheme); + if (HttpContext.GetSiteSettings().GetValue("ExternalLogin:ProviderType", "") == AuthenticationProviderTypes.OpenIDConnect && + HttpContext.GetSiteSettings().GetValue("ExternalLogin:SingleLogout", "false") == "true") + { + authenticationSchemes.Add(AuthenticationProviderTypes.OpenIDConnect); + } + + return SignOut(authenticationProperties, authenticationSchemes.ToArray()); + } + else + { + return LocalRedirect(Url.Content("~" + returnurl)); } - - returnurl = (returnurl == null) ? "/" : returnurl; - returnurl = (!returnurl.StartsWith("/")) ? "/" + returnurl : returnurl; - - return LocalRedirect(Url.Content("~" + returnurl)); } } }