London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!

Mixed-mode authentication - Identity Server/CMS Identity

Vote:
0
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.