Try our conversational search powered by Generative AI!

impersonation during the login process

Vote:
 

Hello,

We are using the EPi_AspNetIdentityUserProvider in order to set the policies to the pages, blocks etc.
But we want to use Azure as the ISP-Provider for Authentfication.
Later on maybe also some more other ISP-Provider

So I in the startup
I'm calling ...

        services
            .AddCmsAspNetIdentity<ApplicationUser>()

and later on i I setup the Azure - Authentification.
The problem came when the user  has been "azure - authentificated".

This is the code - snippet where the user get's  "azure - authentificated" within the OnTokenValidated-Event:

                options.Events.OnTokenValidated = ctx =>
                {
                    var redirectUri = new Uri(ctx.Properties.RedirectUri, UriKind.RelativeOrAbsolute);
                    if (redirectUri.IsAbsoluteUri)
                    {
                        ctx.Properties.RedirectUri = redirectUri.PathAndQuery;
                    }

                    var claims = ctx.Principal.Identity as ClaimsIdentity;
                    var allClaims = claims.Claims.ToArray();

                    var emailClaim = claims.Claims.FirstOrDefault(claim => claim.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress");
                    var emailAddress = emailClaim?.Value ?? "";
                    var roles = AuthentificationRepository.GetUserRoles(aaOptions.AspNetConnectionString, emailAddress);
                    foreach (var role in roles)
                    {
                        Claim claim = new Claim("claims/role", role);
                        claims.AddClaim(claim);
                    }

                    ServiceLocator.Current.GetInstance<ISynchronizingUserService>().SynchronizeAsync(claims);
                    return Task.FromResult(0);
                };


I see two strategies:
-----------------------------
Strategy 1):
  With the "azure - authentificated user" I read the user's roles/claims from the EpiServerDb  and  add the EpiServer-roles/claims  to the "azure - authentificated user" - claims
  I tried this in the code snippet above without success.

Strategy 2):
  With the "azure - authentificated user"  I can archieve a impersonation to a "EPi_AspNetIdentityUserProvider - user"

Do you see any solution how to solve this issue ?

#296576
Feb 15, 2023 14:38
Vote:
 

If using Azure AD or B2C your roles should be managed in that platform and then synched to CMS, (You can still set Access Rights on these Synched Roles). 

    /// <summary>
    /// Azure ad extension
    /// </summary>
    public static class AzureAdExtensions
    {
        /// <summary>
        /// Azure Ad authentication
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <param name="forceHttpsRedirect"></param>
        public static void ConfigureAzureAd(this IServiceCollection services, IConfiguration configuration, bool forceHttpsRedirect)
        {
            services
                .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApp(
                    identityOptions =>
                    {
                        configuration.Bind("AzureAd", identityOptions);

                        identityOptions.Scope.Add("email");
                        identityOptions.TokenValidationParameters = new TokenValidationParameters
                        {
                            RoleClaimType = ClaimTypes.Role,
                            NameClaimType = ClaimTypes.Email
                        };

                        identityOptions.Events ??= new OpenIdConnectEvents();
                        identityOptions.Events.OnTokenValidated = async (context) =>
                        {
                            if (context?.Principal == null)
                            {
                                await Task.FromResult(0);
                                return;
                            }

                            if (!string.IsNullOrEmpty(context.Properties.RedirectUri))
                            {
                                var redirectUri = new Uri(context.Properties.RedirectUri, UriKind.RelativeOrAbsolute);
                                if (redirectUri.IsAbsoluteUri)
                                {
                                    context.Properties.RedirectUri = redirectUri.PathAndQuery;
                                }
                            }

                            await ServiceLocator.Current.GetInstance<ISynchronizingUserService>().SynchronizeAsync(context.Principal?.Identity as ClaimsIdentity);
                        };

                        identityOptions.Events.OnRedirectToIdentityProvider = async (context) =>
                        {
                            if (forceHttpsRedirect)
                            {
                                context.ProtocolMessage.RedirectUri =
                                    context.ProtocolMessage.RedirectUri.Replace("http:", "https:");
                            }

                            await Task.FromResult(0);
                        };
                    },
                    null,
                    OpenIdConnectDefaults.AuthenticationScheme,
                    CookieAuthenticationDefaults.AuthenticationScheme,
                    true);
        }
        /// <summary>
        /// Configure cookie policy
        /// </summary>
        /// <param name="services"></param>
        /// <param name="setCookieDomain"></param>
        public static void ConfigureCookiePolicy(this IServiceCollection services, bool setCookieDomain)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
                options.OnAppendCookie = cookieContext =>
                {
                    if (cookieContext.CookieOptions.SameSite == SameSiteMode.None)
                    {
                        cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
                    }

                    // this should be environment specific
                    if (setCookieDomain)
                    {
                        cookieContext.CookieOptions.Domain = ".localhost";
                    }
                };

                options.OnDeleteCookie = cookieContext =>
                {
                    if (cookieContext.CookieOptions.SameSite == SameSiteMode.None)
                    {
                        cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
                    }
                };
            });
        }
    }

UI Role Provider 

    public class UIRoleProviderAad : UIRoleProvider
    {
        private EPiServer.ServiceLocation.Injected<SecurityEntityProvider> _uiRoleProvider;

        public override bool Enabled { get; set; } = true;

        public override string Name => "UIRoleProviderAAD";

        public override async IAsyncEnumerable<IUIRole> GetAllRolesAsync()
        {
            var uiRoles = await _uiRoleProvider.Service.SearchAsync(null, ClaimTypes.Role);

            foreach (var item in uiRoles.Select(r => new UIRoleImpl(r.Name, "DefaultProvider")))
            {
                yield return item;
            }
        }
    }

Role Model

    public class UIRoleImpl : IUIRole
    {
        public UIRoleImpl()
        {
        }

        public UIRoleImpl(string name, string provider)
        {
            Name = name;
            ProviderName = provider;
        }

        public string Name { get; set; }

        public string ProviderName { get; set; }
    }

Startup.cs

            services.ConfigureAzureAd(Configuration, !_environment.IsDevelopment());
            services.ConfigureCookiePolicy(!_environment.IsDevelopment());
            services.AddTransient<UIRoleProvider, UIRoleProviderAad>();

You can also then Map your roles to virtual roles in appsettings e.g. 

  "EPiServer": {
    "Cms": {
      "MappedRoles": {
        "Items": {
          "CmsEditors": {
            "MappedRoles": [ "WebEditors", "WebAdmins" ]
          },
          "CmsAdmins": {
            "MappedRoles": [ "WebAdmins" ]
          }
        }
      }
    }
#296577
Edited, Feb 15, 2023 15:59
Vote:
 

Hi Minesh,

thanks a lot for your reply. I tested the solution and it already works on my side.

But I think  that the solution fails if you have two ISP-providers (e.g. Azure for inhouse colleques + Google for external employees), what is the future's plan.

Example:

Let's say we have to users:
   - user1 -> inhouse user authentificated in azure to the role ContentEditorGroup1 in azure
   - user2 -> external user authentificated in google to the role  ContentEditorGroup1 in google

Is it not the case that role mapping will fail in that case?

#296578
Feb 15, 2023 17:22
Vote:
 

Have a look at Mixed Mode Authentication I believe if the roles have the same name it should work, although suggestion would be to use unique roles and than map to a virtual role 

https://docs.developers.optimizely.com/content-cloud/v12.0.0-content-cloud/docs/mixed-mode-authentication 

#296579
Feb 15, 2023 17:26
* 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.