In ASP.NET (MVC and WebAPI), how is the User Identity object initialized with the data from the FormsAuthentication cookie?
What I want to do is to use 2 types of authentication, cookie based and a custom header based one. Since the AuthorizeAttribute class only checks the User.Identity.IsAuthorized() method and uses no code specific to FormsAuthentication, then that means all I have to do is to manually setup the User.Identity object, whether in the global.asax or in a DelegatingHandler.
So, how do I setup User.Identity? How does the framework automatically set it up using FormsAuthentication?
Here is a related answer.
Identity can be set in a handler, in a module, or in Global.asax. You can modify it at any point in the request lifecycle, but usually the best place to do it is in PostAuthenticateRequest. At this point, FormsAuthentication has done it's work and you can augment or replace the HttpContext.Current.User.
ASP.NET MVC Controller has a Controller.User but Web API does not have one. It is currenty being requested to be put in.
Related
I would like to know that how [Authorize] attribute recognize that this user is authenticate?
If user is valid then we call FormsAuthentication.SetAuthCookie() method and as per MSDN this method:
Creates an authentication ticket for the supplied user name and adds it to the cookies collection of the response, or to the URL if you are using cookieless authentication.
Is [Authorize] attribute checks authentication ticket or cookies collection?
[Authorize] does not deal with any authentication mechanism itself. It merely looks in the users IIdentity for the IsAuthenticated flag. It will also look in the users IsMemberOf method, for authorization based on roles.
All the work to decode the authentication ticket is done in the early stages of the app pipeline, which sets those flags. By the time the Authorization Attribute methods are called, all that work has already been done and is stored in the users runtime data.
You can easily check the source code for the Authorize attribute, and you will see that it's quite simple in nature. It just returns true or false based on some simple lookups.
It's become more complicated in .net core, where it's based on policies and what not, but the original MVC implementation was quite simple.
My answer relates to ASP.NET Core I'm not sure if you asked about classic ASP.NET but this should be similar.
There's a middleware that you have to add for [Authorize] to work. ASP.NET Core provides this middleware out of the box and you can add your custom authentication handlers too.
You can check how it's implemented by reading: https://github.com/aspnet/Security/tree/dev/src
For example you want to use JWT bearer authentication, you have to add JWT bearer middleware, this is simply extension of AuthenticationBuilder: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerExtensions.cs which calls AddScheme under the hood.
You want to use cookie based authentication you just call AddCookie which is also extension that calls AddScheme under the hood: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.Cookies/CookieExtensions.cs
Usage of it is documented here: https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x?view=aspnetcore-2.1
See also Using the [Authorize] Attribute
Web API provides a built-in authorization filter, AuthorizeAttribute. This filter checks whether the user is authenticated. If not, it returns HTTP status code 401 (Unauthorized), without invoking the action.
If you are interested how this filter works under the hood you can check it here.
You must be authenticated before you can be authorized, this is the logic responsible for it: https://github.com/aspnet/Security/blob/644f34e90d35b369efdce9c11ab1db42e0a7f4a7/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs#L91
In summary
how [Authorize] attribute knows that this user is authenticated.
Authorize attribute alone doesn't know if this user is authenticated. This is handled by authentication middleware and depends stricly on the scheme it tries to authenticate with. It simply tries to authenticate with schemes you have added(cookie,jwt etc.) by calling HttpContext.AuthenticateAsync which is simply calling AuthenticationService.AuthenticateAsync under the hood and sets HttpContext.User from the result ClaimsPrincipal, which is simply result from schema handler like jwt handler for instance. I think this should give you more in-depth idea how this works.
Generally if you're starting new project I don't recommend using classic ASP.NET and prepare for the future with .NET Core as everything is now going in this direction. ASP.NET 5 ( I also refer to it as "classic") is pretty much dead now.
net mvc 5 application using entity frame work etc and am new to .net c# etc (used to php & sessions)
so i have read allot about using .nets authentication service and that is some how registers a user upon login using FormsAuthentication.SetAuthCookie.
however i need to authenticate a user group for example admin or moderator. and from what i understand this can be achieved and be set using [authenticate(roles="admin")].
but surely if this is using a set cookie a user if they knew how could just change their registered role from user to admin to access restricted content?
so in as simple terms as possible how does .net mvc ensure security in authenticating users? can i use sessions instead of cookies? do i need to create my own authentication system.?
i have searched and read all i can find and most resources just explain how cookies work or how to implement authentication using cookies but very little about sessions.
I'll try to be as concise as possible:
Yes, ASP.NET MVC 5 uses cookies out of the box (if you chose Individual User Accounts in the project wizard)
The authorization of a group or role by means of an [Authorize(Roles="bla")] attribute to decorate controllers and/or controller methods will do just that. It's as if you would be writing
if(!User.IsInRole("bla"))
{
return new HttpUnauthorizedResult();
}
else
{
//here's your ultra-secret View
return View();
}
What if a user changes role while in-session or if he or she has a persistent cookie?
Indeed, you'll need to handle the interval between role change and cookie update.
Read up on it here
Long story short: the design decision is yours whether you think it better to log off a user when re-assigning roles or to make db roundtrips at every authorization check.
Can you use a session variable like in PHP? Sure (the Session object exists), but you shouldn't.
If and when the situation arises where you absolutely NEED to pass some arbitrary data however, there's ViewBag, ViewData and TempData.
I won't go as far as to say, that these constructs are superfluous, they certainly have their use from time to time, but do try and design your application to maximize the use of strongly-typed models, viewmodels and make use of the REST-based url architecture to get or put your data.
I am currently implementing a custom membership provider in ASP.NET MVC3 and have been looking at examples of different sample implementations. I have noticed that FormsAuthentication.SetAuthCookie() never seems to be called from the ValidateUser method in the provider. It always seems to be called in the function which calls ValidateUser if ValidateUser returns true. This is usually some form of authentication helper.
What I don't understand is that SetAuthCookie() seems to be called once ValidateUser returns true. So my question is why not just integrate it directly?
This is done because of separation of concerns i guess.
The membership providers responsibility is just to validate whether a given username/password pair is valid or not.
The FormsAuthentication.SetAuthCookie() methods task is to transform that information (the user has authenticated itself successfully) into a serializable format (cookie or url parameter) so that it survives the next HTTP request.
You could replace both implementations independent of each other, storing the authentication information in a cookie is just the most common way on the asp.net platform.
I'm working through a previous webforms application to convert it to MVC and have one big issue that I can't seem to find any good resources about. I want the ability to capture the identity of the user (windows auth set in the web.config) but in the global.asax I can't seem to get access to session (but I can get the identity information). Or when I'm working inside a base class for my controllers, I don't have access to the httpContext in the constructor (but I do have access to session)
Anyone have a good solution for this issue? Previously in webforms I had a master page that did some verification and set some session vars depending on your id/etc
You can always get access to the session, or any other httpContext based entity, so long as they have already been instantiated, by using this line of code
HttpContext.Current.Session
HttpContext.Current.Request
HttpContext.Current.Server
...etc
But also, you should always have access to the User & Identity information without needing to persist it to the session unless you are making modifications to the Identity and storing those modifications separately.
HttpContext.Current.User.Identity
I want to use the the AuthorizeAttribute to control which users are allowed access to my actions. I just want to clarify that my logic is in order.
I create my own implementation of IPrincipal
I post a user's credentials to a login action of a security controller.
I validate the credentials with a UserService class and assign the IPrincipal returned from my UserService class to HttpContext.User
My WebAuthorizeAttribute, which inherits AuthorizeAttribute, checks the current HttpContext.User.Identity.IsAuthenticated and HttpContext.User.IsInRole to determine if the user has access to the action.
Is the the normal flow of things? I know I could inherit MembershipProvider, but I don't need all of the functionality there, really just the ability to login with two different roles.
You'll have to store IPrincipal somewhere and restore it with every request. If you'll use FormsAuthentication, this is good solution:
ASP.NET 2.0 Forms authentication - Keeping it customized yet simple
you can find other solutions here:
Where to store logged user information on ASP.NET MVC using Forms Authentication?
and propably in many other StackOverflow questions:)
EDIT
About MyBusinessLayerSecurityClass.CreatePrincipal(id, id.Name):
You should read this page:
http://msdn.microsoft.com/en-us/library/aa480476.aspx
Specially this:
The
FormsAuthenticationModule
class constructs a
GenericPrincipal
object and stores it in the HTTP
context. The
GenericPrincipal
object holds a reference to a
FormsIdentity
instance that represents the currently
authenticated user. You should allow
forms authentication to manage these
tasks for you. If your applications
have specific requirements, such as
setting the User
property to a custom class that
implements the
IPrincipal interface,
your application should handle the
PostAuthenticate
event. The
PostAuthenticate
event occurs after the
FormsAuthenticationModule
has verified the forms authentication
cookie and created the
GenericPrincipal and
FormsIdentity
objects. Within this code, you can
construct a custom
IPrincipal object
that wraps the
FormsIdentity object,
and then store it in the
HttpContext. User
property.
FormsIdentity is managed automatically after you set authentication cookie. All you have to do is wrap it up in your IPrincipal. All this happens when HttpContext.Current.User property is not null (it is GenericPrincipal, which you replace shortly after). When HttpContext.Current.User is null then there was no authentication cookie created earlier and user is not authenticated.
I believe the following is more typical:
I create my own implementation of IPrincipal
I post a user's credentials to a login action of a security controller.
I validate the credentials with a UserService class and construct a cookie that has some identifying information for this user. Typically FormsAuthentication.SetAuthCookie or some combination of that class's utility methods are used.
In the Application AuthenticateRequest event, inspect the cookie and assign Context.User. Note: This value is automatically assigned to Thread.CurrentPrincipal after the AuthenticateRequest event. This is a one-time assignment and these values are not automatically synchronized thereafter.
My WebAuthorizeAttribute, which inherits AuthorizeAttribute, checks the current HttpContext.User.Identity.IsAuthenticated and HttpContext.User.IsInRole to determine if the user has access to the action.