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" ]
}
}
}
}
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?
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
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 ...
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:
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 ?