I have implemented a token based authentication web Api 2 application using OWIN middleware, authentication is made successfully where I can retrieve token and use it to get to the method of the web Api.
However when I tried to add roles authorization, it doesn't work, I've searched thoroughly and found that I have to add in the "GrantResourceOwnerCredentials " in the oAuthorization provider the following:
identity.AddClaim(new Claim(ClaimTypes.Role, "the role that i need to add"));
The above line is all that I can get, it is also found in Authorization roles WebAPI oauth owin
However still whenever I use a token to get to any method(even authorized ones with different role) it still retrieve results normally.
I mean when for example in the API Controller: it is like the following:
[Authorize(Roles = "Admin")]
// GET api/Patient
public IQueryable<Patient> GetPatients()
while in the "GrantResourceOwnerCredentials" method i have added only an Employee role:
var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
oAuthIdentity.AddClaim(new Claim(ClaimTypes.Role, "Employee"));
Also, the Table in the server explorer that holds the roles "AspNetUserRoles" is not updated.
What I'm missing???
Related
I have created an app which is using Azure AD authentication. After user is authenticated, I want to get the user's unique Id and get the group information which I want to save in a session so then that group information can be fetched in any controller action.
One good place to do that would be right SignIn() method method but this code does not execute because of the cache and user can get to the default page.
So what would be the best possible solution to create the session prior to user start any activity on the application after user is authenticated?
In this page i should be able to check if user is authenticated, username and also get users unique id as follow:
var userName = System.Security.Claims.ClaimsPrincipal.Current.FindFirst("name").Value;
var IsAuthenticated = HttpContext.User.Identity.IsAuthenticated;
var uniqueId = system.Security.Claims.ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
Please Include below in application manifest in azure portal
"groupMembershipClaims": "All",
Change this to "SecurityGroup" to get security groups and Azure AD roles
Or change to "ApplicationGroup". This includes only groups that are assigned to the application.
See groupmembershipclaims-attribute.
Access the group info from controller before routing it to any other controller/ redirect uri in the startup before app authorization.
[Route("api/[controller]")]
[ApiController]
public class CurrentUserController : ControllerBase
{
[HttpGet("groups")]
[ProducesResponseType(typeof(IEnumerable<ClaimsViewModel>), (int)HttpStatusCode.OK)]
public IActionResult Groups()
{
return Ok(User.Claims.Where(claim => claim.Type == "groups").Select(c => new ClaimsViewModel() { Type = c.Type, Value = c.Value }));
}
}
In case where users have more than 5 AD groups, you may have to query the groups manually using MS Graph or save those separately with other alternatives.
References:
net - Get a list of groups that Azure AD user belongs to in claims- Stack Overflow
asp.net - Claim data missing for authenticated users - Stack
Overflow /Azure Web App Authentication using Azure AD – how to get
user’s groups - Stack Overflow
I am having difficulty figuring out how to set the current user in an ASP.NET MVC 5 application that uses ASP.NET Identity.
We use a Web Service that encapsulates authentication. A function calls that service and gets back a JWT token that can be "unwrapped" to retrieve the ClaimsIdentity. It's my understanding that all you should need to do, at that point, is call HttpContext.GetOwinContext().Authentication.SignIn() and pass the ClaimsIdentity to establish the current user and get that user to persist across requests.
However, this doesn't seem to be the case. If I query this.User in the controller or the view afterwards, it's an anonymous user (this.User.Identity.IsAuthenticated evaluates to false). Also, refreshing the page or redirecting makes it obvious that there's no current user (again, this.User.Identity.IsAuthenticated evaluates to false).
When I inspect the identity I've retrieved from AccountHelper, all the data is there. It's fully populated with a name, an ID, and a full suite of claims.
So what is the right way to establish the current user and get it to persist across requests?
// This call authenticates a user with the provided credentials against our user store
// and returns a bearer token and a ClaimsIdentity.
var response = new AccountHelper().AuthenticateUser(credentials);
if (response.IsAuthenticated) // This is true
{
// This comes back with a fully populated identity, as expected.
var claimsIdentity = response.ClaimsIdentity;
// This call has no effect, whatsoever. It doesn't set the current user.
HttpContext.GetOwinContext()
.Authentication
.SignIn(new AuthenticationProperties { IsPersistent = true }, claimsIdentity);
First of all, did you miss .Current in your code sample?
It should be
HttpContext.Current.GetOwinContext()
.Authentication
.SignIn(...);
Secondly, I'm assuming you've setup cookie authentication in your app?
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
...
});
Here setting the authentication type is important! And when you generate the claims identity and before you pass it into the .SignIn() method, the claims identity needs to have the same authentication type so that they can talk!
I would use .CreateIdentityAsync() method from the UserManager class to create the identity instead, because you can pass the authentication type in as one of the parameters:
// Create an application user from your claim identity?
var appUser = new AppUser { ... };
// And pass the user into manager to create the identity with the same authentication
// type you used when you setup the cookie authentication
var claimsIdentity = _userManager.CreateIdentityAsync(appUser,
CookieAuthenticationDefaults.AuthenticationType);
I am using this way to impersonate users for admins that have developer role so that we can test the app.
To enable my service layer to access the current User Id anytime it needs, I use Thread.CurrentPrincipal.
The service layer is used by two front-end layers, one MVC App and one MVC Web Api used for a Mobile App.
In the web app, I use Forms Authentication and the Principal is set into Application_PostAuthenticateRequest. It works fine.
In the web Api, I use Owin. But I cannot find a way to set that Principal after each request is authenticated with the access token.
I can do it when the user logs in with its credentials by overriding GrantResourceOwnerCredentials into my OAuthAuthorizationServerProvider or when he logs with its refresh token by overriding GrantRefreshToken in the same class.
But where could I assign it for requests automatically authenticated with the access token ?
NB. I know that in my Api Controllers I can access the current User, and it is correctly set, but I don't want to pass it with each call to my service layer.
Thanks.
I found how to set it.
The bearer validation is not done by the OAuthAuthorizationServerProvider. I had to implement a custom OAuthBearerAuthenticationProvider, and override the ValidateIdentity method:
public class MyBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
{
public override Task ValidateIdentity(OAuthValidateIdentityContext context)
{
Thread.CurrentPrincipal = new Principal(context.Ticket.Identity);
return base.ValidateIdentity(context);
}
}
And plug that provider into my app by using:
OAuthBearerAuthenticationOptions bearerAuthenticationOptions = new OAuthBearerAuthenticationOptions()
{
Provider = new MyBearerAuthenticationProvider()
};
app.UseOAuthBearerAuthentication(bearerAuthenticationOptions);
Unfortunately Thread.CurrentPrincipal is null in my Business Layer. I assume the token validation is done in another thread than the request execution. So I'll have to change my method.
Is there a way to authenticate a session without creating an ApplicationUser in MVC 5 identity?
For various reasons, I ended up using a two layered authentication system. I parse a "user" object from my custom db into session, and in various places all over the site, the existence of this object is how the logged-in status of a user is determined.
I use Identity user stuff (e.g. claims, logins, etc.) at various places of the site. But at this one specific instance, I need to log in an anonymous Identity user and parse whatever user object is requested to the session. So how can I create an anonymously authenticated session with Identity V2?
In Identity you don't need to have user object to authenticate. You could create some claims on the fly and use them to authenticate. Consider this simple example:
[HttpPost]
public ActionResult AnonymousLogin()
{
var ident = new ClaimsIdentity(
new[]
{
// adding following 2 claim just for supporting default antiforgery provider
new Claim(ClaimTypes.NameIdentifier, "AnonymousUserID"),
new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string"),
new Claim(ClaimTypes.Name, "AnonymousUserID"),
},
DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.GetOwinContext().Authentication.SignIn(
new AuthenticationProperties { IsPersistent = false }, ident);
return RedirectToAction("MyAction"); // auth succeed
}
Now you have authenticated an anonymous user just like a real user:
[Authorize]
public ActionResult MyAction()
{
// all authorized users could use this method don't matter how have been authenticated
// you have access current user principal
var username=HttpContext.User.Identity.Name;
}
Here is my scenario: I have a MVC web application and Web API. Web application making calls to web api for saving/retrieving data from server.
Lets say this is a question/answer web site. Right now I have an API that gives me userid if I provide username, password. But there are other areas in the website and its easy to retrieve other user's userid. I'm keeping the userid in the session storage and sending that in the POST object wherever required. Now any user can tweak that userid in the session storage and they can post the question/answer on behalf of other user.
How I can prevent this? One approach I was thinking but not sure if this is feasible solution - can we retrieve the userid from the supplied bearer token on the server side?
Sure you can do this, once you establish token based authentication in Web API using the resource owner credential flow, and when you attribute you protected controllers with [Authorize]. The valid bearer token you will send to this protected endpoint will create ClaimsPrincipal principal (identity) object where the user is stored in it, you can get the username as the below:
[RoutePrefix("api/Orders")]
public class OrdersController : ApiController
{
[Authorize]
[Route("")]
public IHttpActionResult Get()
{
ClaimsPrincipal principal = Request.GetRequestContext().Principal as ClaimsPrincipal;
var Name = ClaimsPrincipal.Current.Identity.Name;
var Name1 = User.Identity.Name;
return Ok();
}
}
For more detailed information about this you can read my detailed posts about this topic here.