How to get the [Authorize(Roles = "RoleName")] into variable? - asp.net-core

i am trying to save the role from the AuthorizeAttribute in a variable but i cant seem to figure out how. i want something like this. Note: the User/Roles is created from Azure Active Directory
private string CalculateRole()
{
var role = authorize.role;
return role;
}
i searched all over and "closest" i got is this question asp.net identity get all roles of logged in user
but all i get back is a list of Claims I cant find any "roles".

[Authorize(Roles = "RoleName")] is used for access. We can specify the roles that have access to the requested resource using the Roles property of Authorize attribute. For example, [Authorize(Roles = "Admin")] allows us to access the action method to users who are member of "Admin" role.
For the currently signed in user for an application, you can always find the Application Roles assigned to them from the Role claims available as part of the access token from Azure Active Directory.
For more information, here's a sample that uses OpenID Connect to sign-in users and use Azure AD Application Roles (app roles) for authorization. Also, you could use Microsoft Graph API to get the roles.

You can get roles from db by current user id.

You can have a bool validation within the Controller (where HttpContext.User e
bool isAdminUser = User.IsInRole("Admin");
This is fine if you want to validate for specific -or a few- Roles defined. If you have many roles this may not be the best option and you might want to consider to call GraphApi instead for membership validation.

Related

Authenticate AZURE Ad user by App role assigned to the user group

I have created an App role for my AZURE AD Backend Api and assigned this role to a group. Now I want to authenticate user in my .net core backend application on the basis if user has a group which has this role. I am getting the group ids in the access token but how can I get app roles assigned to these groups.
Please check how you enabled group claims in Azure Portal.
If you check the Emit groups as role claims option like below you cannot see application roles, but you can see group ids.
If the above option is enabled, make sure to uncheck the box.
Note
If you use the option to emit group data as roles, only groups will
appear in the role claim. Any application roles that the user is assigned to won't appear in the role claim.
Also, I would suggest you refer to this Microsoft official documentation below which states that if you add a service principal to a group, and then assign an app role to that group, Azure AD does not add the roles claim to tokens it issues.You can modify the “groupMembershipClaims” field in application manifest if you want to include groups claim in your token like below: -
Add app roles to your application and receive them in the token
For more in detail, please refer below link:
Configure group claims for applications by using Azure Active Directory

Handle Authorization and Authentication in DDD

currently i am trying to deal with authorization and authentication on .net core API
There is a company, and that company can create custom roles.
Those roles, will have permissions inside it, such as:
Read
Write
Delete
The company, can apply a role to the users that he creates
With that said, how would i handle the authorization part?
Because, i believe this is considered business logic.
How should i approach this?
Thanks in advance
You can create the role and add claims to that specific role and policy for authorization
AddAuthorization((options) =>{
options.AddPolicy("UserCreation", policy =>
policy.RequireRole("Admin").RequireClaim("Admin", "Edit"));
by using the role manager in.net core identity you can add the claim to the role
RoleManager<Role> _roleManager;
_roleManager.AddClaimAsync(role, claim);
last you can check whether the user have the role and claim to access the resource using authorize attribute
[Authorize(Roles = "Admin", AuthenticationSchemes = "Bearer", Policy = "UserCreation")]
You can probably handle this in multiple different ways. I'd suggest, since you are referring to an API, to decorate the Controllers, Routes or both with the [Authorize] attribute, where you want the rules to apply.
And you would use this attribute as such (where foo, bar, baz - are the roles on the authenticated user).
[Authorize(Roles = "foo,bar,baz")]
You can also define the challange scheme like
[Authorize(Roles = "foo,bar,baz", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
Docs: https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-6.0

How to use IdentityServer4 to authenticate local user from local database?

I'm creating SSO solution for multiple existing projects. Most of the applications already use same database, so same users and I use these users in IdentityServer. But there is one app which has its own users DB and login screen. Users from this table are used in one of the tables in this app (FK).
My idea is to leave existing users DB as is. Add a column MasterUserGuid to Users table that will contain "master" user Guid (so the user that IdentityServer uses for authentication) and implement following flow:
User opens the app and is not signed in
User is redirected to IdentityServer and uses global credentials
User is redirected back to the app which gets global user GUID from claims and authenticates local user (with this GUID in the MasterUserGuid column), instead of using global user
The problem is that I don't know how to implement step 3 or if it's even possible/supported in IdentityServer4. At the moment I'm redirected to IdentityServer, am authenticated and redirected back, but then the app tries to use this external user.
While researching I've read that users should be in one table, so maybe this approach is totally wrong and it would be better to remove local users and break FK for mentioned table and do some manual migration of users.
Is the scenario described in the steps I provided possible and sane?
You need to adjust your application to authenticate via IdentityServer first. Remove all the ASP.NET Core Identity logic related to registration, login etc. assuming all of that will be done on IdentityServer side. Then implement the instance of IClaimsTransformation which will either replace your current ClaimsPrincipalor add additional identities to it if needed with the claim values you want (populated from local database). Here is the example:
public class MyClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var claims = new List<Claim>();
claims.Add(new Claim(...)); // put here your claim type and value
var identity = new ClaimsIdentity(claims);
principal.AddIdentity(identity);
return principal;
}
}
Then register your claims transformer in IOC in Startup.ConfigureServices method:
services.AddTransient<IClaimsTransformation, MyClaimsTransformer>();

Can we restrict users in identity server4 to specific applications?

I am trying to implement IdentityServer 4 for enterprise scenario.
I understand that users are registered against Identity server.
My question is how to give permissions to users against applications, like as users are needed to assign to a particular application, if not assigned application should return unauthorized.
If a user needs to access multiple applications then multiple assignments are needed.
I am looking a way for Identity server to invalidate the submitted token if the user doesn't have access to the application in a single go, even though the challenged token might be valid if it is submitted by other application which the user has access to
Identity Server absolutely handles authorizations on the most basic level. It creates authorization codes and access_tokens that are essential in an applications authorization. Without them you cannot get authorized. Thus for others to claim Identity Server does not do authorizations is flat out wrong.
I came in here a week ago looking for a solution for this very same problem. I want to restrict users to specific applications by not granting them access tokens if they fail to meet certain parameters, in my case a UserClient table. Lucky for you I have a solution. Identity Server 4 implements a few, what they call, CustomValidators that occur at the time of authorization or token creation. They are
internal class DefaultCustomAuthorizeRequestValidator : ICustomAuthorizeRequestValidator
internal class DefaultCustomTokenRequestValidator : ICustomTokenRequestValidator
public class DefaultCustomTokenValidator : ICustomTokenValidator
There name really says it when they get called. Each one contains a single method
public Task ValidateAsync(CustomAuthorizeRequestValidationContext context)
{
return Task.CompletedTask;
}
Notice something? That's is right! It does nothing. Almost as if they are meant to be replaced. (It is).
This is the area that you can add your custom logic to reject the request. CustomAuthorizeRequestValidationContext contains ClientId and User claim information. It also contains a boolean value called IsError. Simply set that to true and whamy! Access denied. You can also set error messages etc. Here is an example that implements the ICustomAuthorizeRequestValidator inface that will restrict a user based on there user Id
public Task ValidateAsync(CustomAuthorizeRequestValidationContext context)
{
var sub = context.Result.ValidatedRequest.Subject.FindFirst("sub");
if (sub != null && sub.Value != "88421113")
{
context.Result.IsError = true;
context.Result.Error = "Unauthorized";
context.Result.ErrorDescription = "You are not authorized for this client";
}
return Task.CompletedTask;
}
Feel free to inject a dbcontext or two to read off of your userclient table. I check the sub claim to be null because this will get hit several times before actual login occurs.
From what I noticed all three behave similar in terms of use, but different in terms of outcome. Setting an error ICustomAuthorizeRequestValidator will prevent the redirect to your client and instead direct you to the Identity Server error screen. The other two will redirect back to the client and generally throw some throw some sort of HttpResponse error. Therefore replacing the ICustomAuthorizeRequestValidator seems to work best.
So simply created a class that implements ICustomAuthorizeRequestValidator. Then add that into your identity services like so
services.AddIdentityServer().AddCustomAuthorizeRequestValidator<MyCustomValidator>()
and you are done done.
You can add a claim in your IdentityServer4's claims table called "role" and in your application, add some UI to authorize a person via email or similar, and then set his/her role in the claims db. And you can also delete the authorized user from your application, which should un-assign a role to that particular person. Thus he/she although is successfully authenticated, can't use your application because you have authorized then. Hope this approach helps you!
For users, IdentityServer is authentication only. Authorization should be handled by your application.
Authentication = Verifying who a user is
Authorization = Verify what a user can do
Update
I wrote an article on this topic to clarify how OAuth 2.0 does is not user-level authorization. Hope it helps! https://www.scottbrady91.com/OAuth/OAuth-is-Not-User-Authorization
As Scott says, Identity Server will authenticate that the user is who they say they are, not explicitly tell you what that user can do.
You can use the claims returned as part of that authentication to then perform authorization checks within your app. For example, you might use the sub or id claims to perform checks from your app on whether the user associated with that sub/id is allowed to access a specific resource.
The water gets a bit muddier when you bring role claims into the picture, but so long as you appreciate the difference between authentication and authorization you should be ok.
In our enterprise scenario we split it into layers:
We introduced a tenant -- a customer (organization) of our enterprise
solution.
Then we have roles (not more than 20 or so) assigned for
each particular user.
IdentityServer fetches users from tenant and access APIs. The only pre-check it performs is that a particular client (application), requested a token, is not restricted for the particular tenant (customer-level licensing), otherwise we display a message and block the challenge response.
Then we come to an app. With a valid token, having tenant and roles inside. The roles-to-functions assignment could be unique within the tenant. So the application itself performs a granulate permissions check, using a separate API. The application is free to enable-disable some functions or even redirect to the special page in IdSrv "Access denied for the app".
With such approach we are scalable, we are configurable, we are as fast as we want. In previous generation we had "all in one" identity+access+licensing monster-like system, and we decided to split. Today we do not face any real limits with adding new customers (tenants), having 20000 users in average each.
Another way, you can redirect user back to respective client login page it they are not assigned to application/client by using IProfileService of IdentityServer4.Services
public async Task IsActiveAsync(IsActiveContext context)
{
if (!string.Equals("MyAllowedApplicationId", context.Client.ClientId, StringComparison.OrdinalIgnoreCase))
{
context.IsActive = false;
}
}
You have to set IsActive = false to redirect user back to login page where user can login with user details which is allowed in application

Role membership creation with ADFS login

I am creating an MVC4 application that uses ADFS SSO login. I am trying to configure Roles so that I can restrict the Admin portion of the content But I am having some problems. I am hoping someone will be able to tell me how I can go about creating Roles when using ADFS? I have the pages restricted successfully I just need now to be able to Add the actual role itself and I am hoping someone can help me out.
In my Global.asax file I have enabled Roles using the code:
System.Web.Security.Roles.Enabled = true;
And on my HomeControllor I tried using the following code:
if (hvm.User.isAdmin == true)
{
if(!User.IsInRole("Admin"))
Roles.AddUserToRole("jpmcfeely", "Admin");
}
This results in the following error:
This method can only be called during the application's pre-start initialization phase. Use PreApplicationStartMethodAttribute to declare a method that will be invoked in that phase.
Any suggestions would be greatly appreciated.
The easiest way is to configure ADFS to map AD groups to roles.
ADFS : Sending groups as claims.
e.g. map "Token-Groups - Unqualified Names" to Roles. Then IsInRole works OOTB.