Can not override path "/Util/Logout" in cms 12

Vote:
 

INFO: I do not use EPiServer.CMS.UI.AspNetIdentity, but Azure AD SSO.

In Optimizely we have an Logout link inside /episerver/cms. It point to /Util/Logout. I want my users to logout using this feature. Now they get an 500 error page if they use it. InvalidOperationException: Unable to resolve service for type 'EPiServer.Shell.Security.UISignInManager' while attempting to activate 'EPiServer.Cms.Shell.UI.Controllers.Internal.AccountController'.

I feel like I have two options. Either to hijack the request to /Util/Logout and run my own logout logic or to change the url. Both solutions should be possible, but I can't get it to work.

In cms 11 it was possible to hijack the request like this

 app.Map(LogoutUrl, map =>
            {
                map.Run(ctx =>
                {
                    ServiceLocator.Current.GetInstance<IAuthenticationService>().SignOut();

                    ctx.Authentication.SignOut();
                    ctx.Response.Write("You are logged out.");
                    return Task.FromResult(0);
                });
            });

I tried to do this in cms 12 but with no luck:

 // TODO not working. This approach worked in aspnet, but not in aspnetcore.
            app.Map("/Util/Logout", map =>
            {
                map.Run(ctx =>
                {
                    ctx.SignOutAsync();
                    ctx.Response.WriteAsync("You are logged out.");
                    return Task.FromResult(0);
                });
            });

A different approach is to change the url, to point to an url I control. 

The logout link is generated inside a [MenuProvider] inside EPiServer.Cms.Shell.UI.Internal.CmsMenuProvider. On line 3 below it seams that it should be possible to change the url by setting the CookieAuthenticationOptions.LogoutPath.

 private void AddLogoutMenuItem(List<MenuItem> menuItems)
    {
      string url = this._cookieAuthenticationOptions?.LogoutPath.Value ?? this._uiPathResolver.CombineWithUtil("Logout");
      if (this._httpContextAccessor.HttpContext != null)
      {
        IAntiforgery service1 = this._httpContextAccessor.HttpContext.RequestServices.GetService<IAntiforgery>();
        IOptions<AntiforgeryOptions> service2 = this._httpContextAccessor.HttpContext.RequestServices.GetService<IOptions<AntiforgeryOptions>>();
        if (service1 != null && service2.Value != null)
          url = url + "?" + service2.Value.HeaderName + "=" + service1.GetAndStoreTokens(this._httpContextAccessor.HttpContext).RequestToken;
      }
      UrlMenuItem urlMenuItem1 = new UrlMenuItem(this._localizationService.GetString("/shell/cms/menu/logout"), "/global/user/logout", url);
      urlMenuItem1.SortIndex = 1010;
      UrlMenuItem urlMenuItem2 = urlMenuItem1;
      menuItems.Add((MenuItem) urlMenuItem2);
    }

I tried this in my Startup.cs

.AddCookie(options =>
            {
                options.ForwardChallenge = SamlAuthenticationDefaults.AuthenticationScheme;
                options.Cookie.SameSite = SameSiteMode.None;
                options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
                options.LogoutPath = "/test/Logout";                
            })

But with no luck. When / how should I set the LogoutPath to make this work? 

#276753
Edited, Mar 20, 2022 20:19
Alan Keegan - Sep 10, 2023 5:38
When testing locally, I found that the Logout menu item URL only gets set correctly when calling services.ConfigureApplicationCookie() in Startup.cs. It doesn't get set when using services.AddCookie(). Not sure why.
Johan Petersson - Sep 10, 2023 8:12
You can have multiple cookie middlewares and they are named options. ASP.NET Identity adds four different cookies. The default cookie ASP.NET Identity uses for authentication, is called 'Identity.Application' and you configure it with services.Configure CookieAuthenticationOptions (IdentityConstants.ApplicationScheme, options => ....) or via services.ConfigureApplicationCookie(o => ...);
Vote:
 

Configuring the CookieAuthenticationOptions.LogoutPath should do it. Do you mind posting your whole configuration in startup.cs? Maybe something else is configuring the options.

#276793
Mar 21, 2022 9:12
Vote:
 

Found this soltuion, using MapWhen (this will stop execution of other midlewares) instead of only Map.


            app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/Util/Logout"), appBuilder =>
            {
                appBuilder.Run(async appBuilder =>
                {
                    await appBuilder.SignOutAsync();
                    appBuilder.Response.Redirect("/", false);                    
                });
            });
#276795
Edited, Mar 21, 2022 11:10
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.