Luca Leonardo Scorcia
Luca Leonardo Scorcia

Reputation: 475

SignOut does not redirect to site home page

I'm trying to setup an ASP.net Core 3 MVC app that uses OIDC to connect to my company's SSO portal (OpenAM).

I used Visual Studio 2019 project generator to create a basic app with no authentication and then I added the OIDC client capabilities following the steps at http://docs.identityserver.io/en/latest/quickstarts/2_interactive_aspnetcore.html#creating-an-mvc-client . Logging in works great with minimal changes to the Startup class:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();

        // Setup Identity Server client
        JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

        services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.Authority = "https://mycompany.com/ssoservice/oauth2";
                options.RequireHttpsMetadata = false;

                options.ClientId = "openIdClient";
                options.ClientSecret = "secret";
                options.ResponseType = "code";
                options.ProtocolValidator.RequireNonce = false;

                options.SaveTokens = true;
            });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            IdentityModelEventSource.ShowPII = true;
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            // endpoints.MapDefaultControllerRoute();
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }

I also set up a Logout controller action:

    [Authorize]
    public IActionResult Logout()
    {
        return SignOut("Cookies", "oidc");
    }

The action actually works, i.e. when activated the cookie is deleted and the user is logged out from the SSO portal, but when the browser redirects to the /signout-callback-oidc endpoint it receives an HTTP 200 response without any content. I would have expected to have it automatically redirect to the site home page "/", which is the default value of the OpenIdConnectOptions.SignedOutRedirectUri property.

What am I missing?

Upvotes: 3

Views: 11141

Answers (2)

Luca Leonardo Scorcia
Luca Leonardo Scorcia

Reputation: 475

Ok, after fiddling some more time, I found out this is the result of a missing draft implementation in the latest community OpenAM release (and also in the current paid ForgeRock AM, but they are working on it: https://bugster.forgerock.org/jira/browse/OPENAM-13831). Basically, the .net core handler for /signout-callback-oidc relies on having the state parameter available in order to redirect, like Ruard van Elburg mentioned in the comments:

https://github.com/aspnet/AspNetCore/blob/4fa5a228cfeb52926b30a2741b99112a64454b36/src/Security/Authentication/OpenIdConnect/src/OpenIdConnectHandler.cs#L312-L315

OpenAM does not send back the state parameter, as reported in my logs. Therefore, we need to perform the redirect ourselves - the most straightforward way seems to be using the OnSignedOutCallbackRedirect event:

Startup.cs

    services.AddAuthentication(...)
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            ...
            options.Events.OnSignedOutCallbackRedirect += context =>
            {
                context.Response.Redirect(context.Options.SignedOutRedirectUri);
                context.HandleResponse();

                return Task.CompletedTask;
            };
            ...
        });

Thanks to all the users that replied to the discussion, your contributions allowed me to find the clues to the correct solution.

Upvotes: 10

J S
J S

Reputation: 899

you return SignOut,

instead, SignOut user and return RedirectToAction("Home","Index")

Upvotes: 1

Related Questions