how to get claims of another user using ASP.NET Core - c#

I'm still learning identities with asp.net core. I'm doing a claims-based token authorization.
Most examples are about "Current" logged in user. In my case my RPC service is receiving a username & password of some user in the identity DB. I need to
verify that a user with such credentials exist
get all the claims of that user
so to verify if the user exists, I'm using this:
ApplicationUser applicationUser = await _userManager.FindByNameAsync(username);
bool exist = await _userManager.CheckPasswordAsync(applicationUser, password);
if (!exist)
{
// log and return
}
I don't know how to do the 2nd step properly. I guess I could do a simple linq to collect all user's claims, but I'm sure there is a better way using the identity methods.

You need to use the GetClaimsAsync() method. For example:
var claims = await _userManager.GetClaimsAsync(applicationUser);
See MSDN

Related

Authentication/Authorization in ASP.NET Core using Enterprise SingleSignon page and Microsoft SignInManager

Presently I am working on an authentication issue in one of my ASP.NET Core(3.0) application.
To give some background, we have to use an Enterprise Single sign on page to authenticate the users. Once the user got authenticated it redirects back to our application along with user name in a HTTP header called "SM_USER". Then using that information we load corresponding Claim information from DB using Microsoft SignInManger. The application is working fine if the user is accessing the root but it couldn't able to access if they are trying to navigate a specific page directly, like http://website/Controller/Index.
I am suspecting that we may have implemented it wrongly so would like to know how should the below scenario to be implemented?
Our users first get authenticated using an enterprise Login Page(Single sign on) then redirected to our application. user information available on HTTP Headers and the corresponding claims information is available in our DB which we need to use for authorization purpose(we wanted to use Microrosoft SignInManger to load them).
I found the issue after researching it throughly so sharing here in case it useful for someone.
we observed whenever a user try to access a page if the user is not authenticated then it is redirecting Login page(Observed that decorating them with [Authorize] attribute is causing this), where We are using this Login page for local development purpose.
so when the user get redirected to login page and if the environment is not development then below code is executed on the Get method, which takes care of signing the user and creating UserPrincipal. Then after that we redirecting to the page the user requested.
if (!_signInManager.IsSignedIn(User))
{
string userName = HttpContext.Request.Headers["SM_USER"].ToString();
if (userName.Length > 0)
{
var user = await _userManager.FindByNameAsync(userName);
if (user != null)
{
var claimsPrincipal = await _signInManager.CreateUserPrincipalAsync(user);
await _signInManager.Context.SignInAsync(IdentityConstants.ApplicationScheme,
claimsPrincipal,
new AuthenticationProperties { IsPersistent = true });
if (string.IsNullOrEmpty(returnUrl)) //returnUrl is a parameter get passed by the system.
{
return RedirectToAction("<Action>", "<Controller>");
}
else
{
return Redirect(returnUrl);
}
}
}
}

Id token does not contain email when email scope is requested

I have an identity server 4 application and I have added to the email scope [IdentityResources] table in the database. I have also added the email scope to the client that i am using with my client application.
The client application is now prompting the user for email scope consent after login.
I can also see that its there in the UserClaimsPrincipalFactory
protected override async Task
GenerateClaimsAsync(ApplicationUser user)
{
var identity = await base.GenerateClaimsAsync(user);
if (user.IsXenaSupporter)
identity.AddClaim(new Claim("Supporter", user.Id.ToString()));
return identity;
}
Identity does contain email. Yet when the Id token and access token are returned to the application neither contain an email. Nor is there an email when i reqeust it from the user info end point.
What do I need to do to populate email address in the claims when the application requests the email scope? Also my custom supporter claim is also not being added
The simple fact that the client application is prompting you for the email scope only means, that the scope was allowed in IdentityServer and requested on the client end but not necessarily that this information is being retrieved.
The magic is in the GetProfileDataAsync method of your IProfileService implementation.
This profile service is where you retrieve whatever claims you'd like and add them to the ProfileDataRequestContext.
public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var subjectId = context.Subject.GetSubjectId();
Guid.TryParse(subjectId, out Guid g);
//whatever way or wherever you retrieve the claims from
var claimsForUser = idRepo.GetUserClaimsBySubjectId(g);
context.IssuedClaims = claimsForUser.Select(c =>
new Claim(c.ClaimType, c.ClaimValue)).ToList();
return Task.FromResult(0);
}
As explained here, an id token should pretty much only have a sub claim - that's what the userinfo endpoint is for.
The problem was that i had only added it to the [IdentityResources] table.
This simply defines the different scopes. But it doesn't actually assign any data.
To do that i needed to add it to the [IdentityClaims] table.
As soon as i did this the data started being returned in the claims.

How do I build a custom role based authorization in ASP Core 2?

I have a database that has a user table, access table and a join table assigning a user to multiple access. The site will verify a user by matching the Identity Username from AD with an username in the Users table to verify they can see the site (Intranet). The access table is used to specify which pages they are allow to visit.
In ASP Core 2 how can I use Authorization to perform the same check at Startup to verify they are in the Users table and then take it a step further and use Roles to allow the user access to specific web pages.
I've gone through the documentation but I can't figure out which way to go as the examples use a login that is not necessary in my case using AD.
I have a users table and don't use AD roles because we have a admin for exchange and I do not have access to that.
Thanks in advance
Authorize attribute is the what you are looking for. For example,
[Authorize(Roles = "Admin, User")]
If you are using OAuth for authentication, you will create a ClaimsIdentity while authenticating. Based on the claim, the Authorize attribute will work out of the box. For example,
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(oAuthIdentity);
}
You can refer to this post, where I have explained a similar scenario in a bit more detail.

Asp.net Identity 2.0 custom login method

I'm developing ASP.NET 5 application using Identity 2.0. I have two types of users:
Normal - they authenticate using standard login method.
Temporary - they should login based on provided token.
I do not want to store temporary users, except from information required to authenticate user (some username and token). If the user provides username and valid password he should be logged in.
I'm not sure how to achieve this.
You could use Identity in both scenarios simultaneously as well. For first scenario use Identity just like you have done before without any change but for second scenario you a slight modify in login method.
public ActionResoult TempLogin(string username, string password)
{
// imaging you have own temp user manager, completely independent from identity
if(_tempUserManager.IsValid(username,password))
{
// user is valid, going to authenticate user for my App
var ident = new ClaimsIdentity(
new[]
{
// adding following 2 claim just for supporting default antiforgery provider
new Claim(ClaimTypes.NameIdentifier, username),
new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string"),
// an optional claim you could omit this
new Claim(ClaimTypes.Name, username),
// you could even add some role
new Claim(ClaimTypes.Role, "TempUser"),
new Claim(ClaimTypes.Role, "AnotherRole"),
// and so on
},
DefaultAuthenticationTypes.ApplicationCookie);
// Identity is sign in user based on claim don't matter
// how you generated it Identity
HttpContext.GetOwinContext().Authentication.SignIn(
new AuthenticationProperties { IsPersistent = false }, ident);
// auth is succeed,
return RedirectToAction("MyAction");
}
ModelState.AddModelError("", "We could not authorize you :(");
return View();
}
Since we injected our logic to Identity, we don't need to do extra thing at all.
[Authorize]
public ActionResult MySecretAction()
{
// all authorized users could use this method don't matter how has been authenticated
// we have access current user principal by calling also
// HttpContext.User
}
[Authorize(Roles="TempUser")]
public ActionResult MySecretAction()
{
// just temp users have accesses to this method
}
You'll need to extend the ASP.NET Identity Libraries, using your custom logic and/or storage.
Here you can find an example in my Github account with some useful links that I used to read when I was trying to understand the ASP.NET Identity stuff: https://github.com/hernandgr/AspNetIdentityDemo
Hope it helps!

Mvc OAuth2 how to store data for the current Autentication in a OAuthAuthorizationServerProvider

im sorry for my bad English, im french.
I will try to explain my question the best i can.
i have a OAuthAuthorizationServerProvider wish work fine.
This is to allow other application to connect with my Asp.Net Identity 2.0 Authentication Server.
I wish to store data for the current authentication. If the user is connected twice, they will not necessary have the same stored data. I don't think Session is the right thing for this becose i dont use cookie. I use Bearer, an access_token and a refresh_token.
I can simply store the refresh_token in a table, then refer it on each request but i don't like to store sensible data like that, especially if the framework provide a way to do what i want.
I need to store the data relative to each external authentication, not to the user. Something like Claims but only for the current authentication session.
tanks to point me on the right path.
In your OAuthAuthorizationServerProvider, you will have overridden the GrantResourceOwnerCredentials method. This is where you will have validated the user, and it's the place where you can add additional claims for the user.
Here is an example that validates the user against ASPNet Identity, and adds an additional claim to the identity that is returned.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var mgr = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = await mgr.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
var usrIdentity = await mgr.CreateIdentityAsync(user, context.Options.AuthenticationType);
foreach (var c in usrIdentity.Claims)
{
identity.AddClaim(c);
}
//
// Add additional claims to your identity
//
identity.AddClaim(new Claim("your_custom_claim", "your_custom_claim_value"));
context.Validated(identity);
}
That said, in your comments you seem to be using Cookie and Token in the same sentence, and possibly confusing the two. Check out this blog post which should give you a good example.
Also check out the ASP.NET Identity Recommended Resources page too.

Categories