A classic challenge in Optimizely CMS (well, really in any system I guess), is to ensure that the right people have the right access - and that potentially dangerous actions can't be accidentally done by unqualified users.
Generally, Optimizely CMS 12 is pretty good at ensuring the ability to set granular permissions all over the edit-interface. It's easy to define who can do what to a content item for example.
However, sometimes you miss something. Like in the case of the Optimizely Content Graph integration to CMS 12, the "Reset Index" is available to pretty much all editors. Now, if you've build a headless implementation heavily relying on the Graph as the content source (which is actually a pretty good setup as far as headless goes), then having an editor accidentally reset a production index can be a pretty devastating thing.
Now, obviously I have reported this and hopefully it'll be fixed - but until then, here's a workaround - and the same workaround can easily be adjusted to add granular permissions to any existing functionality you want.
It relies on the Admin area called "Permissions for functions" where you can easily define your own permission types and let administrators assign specific users/roles to them.
In this case combined with a middleware that checks for the right permission before allowing editors access to a given url.
For this case I'm just defining permissions for the reset content graph page like this:
[PermissionTypes]
public static class EditorAccessPermissions
{
public static PermissionType ResetContentGraphIndexPermission { get; } = new PermissionType("EditorAccess", "ResetContentGraphIndex");
}
And that's enough to have the permissions show up on it's own tab in "Permissions for functions".
And then it's pretty straightforward to setup a middleware to check permissions for a given path (but you can customize it to whatever you need):
public class EditorAccessMiddleware
{
private readonly PermissionService _permissionService;
private readonly RequestDelegate _next;
public EditorAccessMiddleware(RequestDelegate next, PermissionService permissionService)
{
_next = next;
_permissionService = permissionService;
}
public async Task InvokeAsync(HttpContext context)
{
var path = context.Request.Path.Value;
// Example: Protect Content Graph Index reset
if (path.StartsWith("/EPiServer/ContentGraph/GraphQLAdmin", StringComparison.OrdinalIgnoreCase))
{
if (!_permissionService.IsPermitted(context.User, EditorAccessPermissions.ResetContentGraphIndexPermission))
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync("Access Denied");
return;
}
}
await _next(context);
}
}
Now you just have to register it using app.UseMiddlewarea<>() in your startup - but remember to set it right after app.UseAuthentication(); and
app.UseAuthorization();