November Happy Hour will be moved to Thursday December 5th.

Mixed-mode authentication - Identity Server/CMS Identity

Vote:
 
I am struggling with getting mixed-mode authentication working in CMS12, we have an Identity Server that is accessed via OpenIdConnect for members to login via the website /login route, and we also need to retain the normal CMS ASP.Net Identity for logging into the CMS. I can get the members /login to work fine, but the login via the CMS then does not work, I see the login page but upon login I am just returned to the login page with no error messages shown. 

The code I have in my startup class as a middleware extension is below:
namespace xxx.Web.Infrastructure.ServiceExtensions;

using System.Text;

using xxx.Features.Common.Configuration;
using EPiServer.Cms.UI.AspNetIdentity;

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

public static class UserAuthenticationServiceExtensions
{
    private const string AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme;

    private const string ChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; 

    public static IServiceCollection AddUserAuthentication(
        this IServiceCollection services, 
        IWebHostEnvironment environment, 
        IConfiguration configuration)
    {
        services.AddCmsAspNetIdentity<ApplicationUser>();
        services.AddIdentityServer(configuration);

        return services;
    }

    /// <summary>
    /// Sets up authentication based on Identity Server 4 using Open ID Connect
    /// </summary>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    /// <returns></returns>
    public static void AddIdentityServer(this IServiceCollection services, IConfiguration configuration)
    {
        var identityServerSettings = configuration.GetSection(nameof(IdentityServerSettings)).Get<IdentityServerSettings>();
        var authority = identityServerSettings?.Authority ?? string.Empty;
        _ = bool.TryParse(identityServerSettings?.RequireHttpsMetadata ?? "true", out bool requireHttpsMetadata);
        var clientId = identityServerSettings?.ClientId ?? string.Empty;
        var clientSecret = identityServerSettings?.ClientSecret?? string.Empty;

        services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = AuthenticationScheme;
                    options.DefaultChallengeScheme = "policy-scheme";
                })
                .AddCookie(AuthenticationScheme, options =>
                {
                    // Defines a path to redirect the user to if they don't have access to a page.
                    // This page should return a 200 response so as to not cause authentication loops.
                    options.AccessDeniedPath = new PathString("/no-access");
                })
                .AddOpenIdConnect(ChallengeScheme, options =>
                {
                    options.SignInScheme = AuthenticationScheme;
                    options.SignOutScheme = AuthenticationScheme;
                    options.ResponseType = OpenIdConnectResponseType.Code;
                    options.CallbackPath = "/signin-oidc";
                    options.UsePkce = false;

                    options.Authority = authority;
                    options.RequireHttpsMetadata = requireHttpsMetadata;
                    options.ClientId = clientId;
                    options.ClientSecret = clientSecret;

                    options.Scope.Clear();
                    options.Scope.Add(OpenIdConnectScope.OpenId);
                    options.Scope.Add("xxx");
                    options.MapInboundClaims = false;

                    options.Events.OnRedirectToIdentityProvider = context =>
                    {
                        // Prevent redirect loop
                        if (context.Response.StatusCode == 401)
                        {
                            context.HandleResponse();
                        }

                        if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                        {
                            var idTokenHint = context.HttpContext.User.FindFirst("id_token");
                            if (idTokenHint != null)
                            {
                                context.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                            }

                        }

                        return Task.CompletedTask;
                    };

                    options.Events.OnAuthenticationFailed = async context =>
                    {
                        context.HandleResponse();

                        await context.Response.BodyWriter.WriteAsync(Encoding.ASCII.GetBytes(context.Exception.Message));
                    };
                })
                .AddPolicyScheme("policy-scheme", null, options =>
                {
                    options.ForwardDefaultSelector = ctx =>
                    {
                        if (ctx.Request.Path.StartsWithSegments("/episerver", StringComparison.OrdinalIgnoreCase))
                        {
                            return "Identity.Application";
                        }

                        return OpenIdConnectDefaults.AuthenticationScheme;
                    };
                });
    }
}
The Authentication controller for the front-end users has been decorated with the following attribute:

[Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)]

I have referenced the following Optimizely page https://docs.developers.optimizely.com/content-cloud/v12.0.0-content-cloud/docs/mixed-mode-authentication but after trying various ways I still cannot get it to allow me to login via the /login method as well as being able to login via the /episerver/cms method.

Does anyone have any experience of successfully implementing mixed-mode authentication in CMS12, or anyone who can provide any pointers/help.

Thanks in advance.
#295653
Edited, Jan 31, 2023 13:25
* 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.