How to authorize the users (with specific membership, user group or claims) to my applications by Azure ad b2c? - authorization

I have a react app as my client app and an asp.net api as my api. I have managed to integrate Azure ad b2c login into my client app. I can attach the acquired access token (from Azure ad b2c) to a request that will be sent to my api and this works fine. I have access to my api with and can use resources in my api.
[Authorize]
[Route("[Controller]")]
[ApiController]
public class StudentController : Controller
{
[HttpPost]
public async Task<IActionResult> CreateStudent([FromBody] CreateModel model)
{
some functions...
}
}
But my question is that how I can restrict/authorize the users by claims/user group to have access to my api. I know that I can't use application/user role in Azure ad b2c But there are maybe some other solutions by claims and/or user group. I really appreciate any help :)

Please check if below points can give an idea to work.
You can try to add custom attributes in the AADB2C .Later check custom claims in Azure AD B2C where the consumer can select required roles during the signup process which is later returned in the token. Please refer to documentation for more details.
If not , one may need to get group member claims from the Microsoft graph api in code configuration and try to for backend api token in code by retrieving from graph and then authorize.
Something like below (see references for further details) in start up class configureservices method .
ex: Role-based-Authorization- denious/Azure-B2C (github.com)
// get authenticated user ID
var subjectId = identity.FindFirst(ClaimTypes.NameIdentifier).Value;
// query user roles
var client = _serviceProvider.GetRequiredService<MSGraphClient>();
var roles = await client.GetUserRolesAsync(subjectId);
// add roles to identity's claims collection with the right type
foreach (var role in roles)
{
var roleClaim = new Claim(identity.RoleClaimType, role);
identity.AddClaim(roleClaim);
}
Please check below references for work arounds.
Authorize By Group in AAD B2C - Stack Overflow or Azure AD B2C - Role management - Stack Overflow
Add claims into token Azure B2C - Stack Overflow
Using custom claims for Azure AD B2C roles - DEV Community

Related

B2C Authenticate User In Web Api

I have a web app where a user logs in through b2c and have certain claims set once they're logged in. Now, I also need to call an api with javascript when a user clicks a button. So that's all fine but, here's my question:
How would I get the user's claims in the api?
My api and client side web app are both in asp.net core.
Thanks in advance!
At first, you may refer to this document or this official sample to check if it met your requirement.
For the api, it will return user information which is signed in the app.
[HttpGet]
public IEnumerable<Todo> Get()
{
string owner = User.Identity.Name;
return TodoStore.Values.Where(x => x.Owner == owner);
}

How to get the [Authorize(Roles = "RoleName")] into variable?

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.

How to receive the current user with create react app -auth template on net core 3 and identity server

I have never used identity server before and I was wondering how to receive the current user info if they have been authenticated using net core 3.
Using the barebones create react app -auth weather app template
in the WeatherForecastController we have the authorize attribute:
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
With the following endpoint:
[HttpGet]
public IEnumerable<WeatherForecast> Get()
Which will return the correct data if you have logged in and been granted a jwt bearer token.
I would like to create an endpoint that:
1. Allows anonymous access(logged in or not so the authorize attribute needs ditching or overriding)
2. It should then try to authenticate the user
3.If the user can be identified then the endpoint will return the correct data else if the user cannot be identified it will return a subset of the data
I'm struggling to retrieve the user who has made the request information, I believe i'm supposed to use GET /connect/userinfo identityserver endpoint with the bearer token as a parameter but I have no idea how to do this. I would like to access the user_id so I can corrispond with the identityUser table.
I have also tried:
var identity = (ClaimsIdentity)User.Identity;
IEnumerable<Claim> claims = identity.Claims;
It just feels like theres a proper way to do this stuff that i'm missing. I'd be grateful for someone to point me in the right direction.
It should then try to authenticate the user
Browsers communicate with web applications. You should have a web application to be able to redirect back to IDS4 to login. What you are have is an API. Later Web applications communicate with web APIs. Read more here
If the user can be identified then the endpoint will return the correct data else if the user cannot be identified it will return a subset of the data
What you are looking for is Authorization, you can manually do this check on the endpoint. You can access current user using ControllerBase.User ass a result of passing a valid JWT tokens to the API. Considering you already setup authentication using code like bellow:
services.AddAuthentication("Bearer").AddJwtBearer("Bearer",
options =>
{
options.Authority = "http://localhost:5000";
options.Audience = "api1";
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"//To set Identity.Name
};
});
I'm struggling to retrieve the user who has made the request information
You can simply use ControllerBase.User to get the current authenticated user on API, no need to call any endpoint.
Update: Setting NameClaimType as posted on code above will set Identity.Name to the user's identifier.

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>();

Claims based authorization token in Azure B2C and .Net Core 2.0

I am building a ASP .Net Core 2.0 app and would like to know how to add the groups claim to my Azure B2C access token on my backend. I use the user's id to query MS Graph to get the user's group claim using ADAL and need the groups on the authorization token every time the user hits a controller. I would rather not query MS Graph every time a controller is hit.
Is it possible to add the groups claim to the B2C token after it is retrieved?
If not, should I store the groups as a Session variable?
If those aren't right, should I craft a second authorization token with the groups and then use that in my header when I send reqeusts?
You can in one of the OpenID Notifications (i.e. OnTokenValidated) and add user's groups(or roles ,but they are different ) to the ClaimsPrincipal. Something like :
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = ctx =>
{
//query the user's groups using api
// add claims
var claims = new List<Claim>
{
new Claim("groups", xxxx-xx-xx)
};
var appIdentity = new ClaimsIdentity(claims);
ctx.Principal.AddIdentity(appIdentity);
return Task.CompletedTask;
},
};
Below links are code sample with .net framework , you can modify to fit the .net core version :
Authorize By Group in Azure Active Directory B2C
Azure AD B2C - Role management
You can support adding group claims to b2c issued tokens by voting for it in the Azure AD B2C feedback forum: Get user membership groups in the claims with Azure AD B2C