Custom Authorize Attribute for my own mgmt API
# package-development
w
Custom Authorize Attribute for my own mgmt API
How do I do something like this in V14 ?
[Authorize(Policy = AuthorizationPolicies.SectionAccessContent)]
But instead I want to check my own custom section, or in my case checking if the user has the new custom content/document permission I added with a TS manifest to the user group/current user? @Sven Geusens or @Bjarke Berg
m
Replying so I can updates πŸ™‚
w
@Kevin Jump is this something that you might have done already ?
k
I'm not sure we've done g it beyond setting section stuff yet, is something I need to do however especially for translations. Something like? policy.RequireClaim(Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Settings);
But with your section name?
w
Yes for a custom section
But also for a custom permission added to a content node
Which don't seem to be set as claim
The sections are though from what I can tell
OK think I found some C# general docs to try and follow along with as my first attempt for lunchtime hack
One for feedback though for CMS core team, be good if we had a semi generic Authroize Attribute that was like. Means it would stop people having to develop their own policy, requirement etc, if I understand the bits I skim read so far...
[HasSection("mySectionAlias")]
s
So we are trying to step away from generic authorize Attributes in favor of policies as that is the .net way of doing things. So how do you add your own? There are a few ways, below is A way, this is not tested ( i should at some point and write some docs, but the asp core docs should cover all of this already, except for our base classes). We do it this way because storing all umbraco permission for a user in the claims will make that token to big, especially when you think about granular permissions (for example: specific read/write permissions for x amount of nodes) [Incomming soon]
w
Yeh found some MSDocs to read tonight (ran out of time at lunch, reporting some other issues/bugs) But be curious on how to read a permission I have added. To see if the user has my custom permission enabled in general on the user group or on a specific content node if overriden ?
Again untested, but this should give you a nice start
w
Thanks will take a look/read tonight or tomorrows lunchtime hack
s
You could condense the handlers into 1 by setting an enum on the requirement with All/Any And then branching the code inside the handler based on that enum value
Calling the policy would be the same, you would just set the enum value when registering the policy
Let me know if I forgot something/made a mistake as I will probably use this as one of the examples/tutorials to give to the docs team to polish off πŸ˜‰
w
Cheers Sven, appreciate it πŸ˜„
s
Had to do something while waiting on performance testing 🀣
w
Interesting its this
_authorizationService.AuthorizeResourceAsync
and not decorating it with an attribute like others ?!
Just interesting I have to put that logic into the controller action/method. I thought it was all about slim controllers @User ?!
Any explicit reason this needs to be set in your example ?
policy.AuthenticationSchemes.Add(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
Again just poking around. Could I reuse this, rather than do all the plumbing suggested above?!
Copy code
csharp
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
            User,
            ContentPermissionResource.WithKeys(ActionMove.ActionLetter, new[] { moveDocumentRequestModel.Target?.Id, id }),
            AuthorizationPolicies.ContentPermissionByResource);
So rather
ActionMove.ActionLetter
I use my string/verb for the permission ?!
Just seeing if I can reuse what's there before I absolutely have to do plumbing
Ideal world for me as package dev, but still reading/learning...
Copy code
csharp
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("HasExaminePeekEnabled", policy =>
        policy.Requirements.Add(new CheckDocumentPermision("HasExaminePeekCustomPermissionVerb")));
});
Then I could use a C# attribute on the controller
[Authorize(Policy="HasExaminePeekEnabled")]
Well I have this silly Policy just so I could be sure I learnt the basics, before diving deeper πŸ˜› I present to you the super useful IsWarren policy
Copy code
csharp
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("IsWarren", policy =>
    {
        // For simple stuff - saves writing a requirement and handler
        policy.RequireAssertion(context =>
        {
            // Simple example to check the Given Name claim contains Warren
            // So if you change the name of your user to include warren it will pass
            // Other simple example could be to check the domain
            // of the email address found 'context.User.Identity.Name'
            return context.User.GetClaim(ClaimTypes.GivenName).ToLower().Contains("warren");
        });
    });
});
Then on my controller
[Authorize(Policy = "IsWarren")]
What is the custom interface
IPermissionResource
used for in Umbraco in your sample (as not in the general .NET docs) @User So curious why I would want/care about it?
s
Sorry, ill try to come back to this tonight πŸ™‚
As far as I understand it, this makes the policy available when authorizing withing the OpenIddict scheme, if you setup another validation scheme this policy would not be applied to it.
w
I will be looking at this lunchtime if I can today - not used your full end to end example, just been learning from MSDocs and trying to apply stuff
I tried this out but forr whgatever reason when authing with Swagger the ideentity was not authenticated?! https://github.com/Gibe/Playmaker/pull/259#discussion_r1647664183
s
I have been trying to massage this into an attribute, but am currently stuck at getting a constructed user from the httpcontext...
w
Thanks for update Sven
I haven’t had time to look and hack anymore. But be good to swap any notes you have @Sven Geusens
s
I was being an idiot, it's fine, it's fine. Got it properly failing trough an attribute.
@Warren Buckley It works!
This shows it working, added the whole swagger setup thing as well, but it's pretty well covered in the docs https://docs.umbraco.com/umbraco-cms/reference/custom-swagger-api Hit the post method, then log out of the backoffice, log back in as a user of the admin group and the 2 other endpoints should work as expected https://cdn.discordapp.com/attachments/1252367722109472909/1260585390474133567/sample_controller.txt?ex=668fdb21&is=668e89a1&hm=ceedc79e2b72b9c7ff72e955d0b59b0a6eccc94df8aeb29935cff2783dc4e986&
Forgot a few renames from Granular to Contextual, sorry
w
Yeh probably makes sense to IMO and will make stuff easier rather than package devs shipping something like this
Thanks will try tomorrow realistically
@Sven Geusens is there an issue or PR to follow along with. I know wont get an answer from team with it Scandi holiday season for a bit, but be good to know whats happening
s
Not yet, was me just trying this out as I will need it for xstatic too
@User still in draft, hopefully a proper PR at the end of the day: https://github.com/umbraco/Umbraco-CMS/pull/16847
w
OOOH I still havent got around to trying this out
Thanks for the update will keep my eyes peeled πŸ‘€
s
Some other more urgent things crept up, so no final PR yet. Good progress on making it better though.