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.
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.
Is there a way to add custom claim to my ClaimsPrincipal once the user is authenticated? When using ASP.NET identity for individual accounts, one could add custom claims to the ClaimsPrincipal when the principal was created but I can not find the way to do this when using the Organizational Accounts template.
For organizational account authentication, the templates setup HTTP handlers to handle authentication of your users. If you look in your web.config you will see two modules that were added to your project, which are the WSFederationAuthenticationModule and the SessionAuthenticationModule. As such, it's an entirely different authentication and authorization dance than what you are used to with cookie based authentication for individual accounts.
The extensibility point you are looking for is the Authenticate method of the ClaimsAuthenticationManager. Simply create a class that derives from this and override the Authenticate method. This will give you access to the ClaimsPrincipal object for the authenticated user where you can extend the claims collection for the user to whatever you want before your application code is invoked.
An example of how to set this up is here.
You do need to sign the user back in.
By default your claims are encrypted and stored as a single cookie in your browser. After you've manipulated your ClaimsPrincipal you need to persist the cookie back to the browser.
I agree the verbage is bad however you have to do the following
var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
var authenticationProperties = new AuthenticationProperties { IsPersistent = false };
authenticationManager.SignIn(authenticationProperties, myManipulatedClaimsIdentity);
I am using WIF and claims-based security in a MVC app and custom logic to create a ClaimsPrincipal with the appropriate claims after they authenticate. I assign some standard claims like Role and Name to the principal but also assign custom claims where applicable.
I modeled my custom claims after the standardized Role and Name claims using a URI, for example
new Claim("http://schemas.acme.com/2012/04/identity/claims/create", "http://schemas.acme.com/2012/04/identity/resources/customer")
Everything has been working very well. I use the SessionAuthenticationModule to store the users session in cookies and rehydrate it on each request.
I noticed today that my custom claims are not deserialized from the cookie after someone logs in with the same usertype. The standard claims (Name/Role) are present but the custom claims aren't.
Has anyone else ever seen this or know why this is happening?
Turns out I was adding the claims that were disappearing by reference. I had a class with static claims pre-defined that I would add to the ClaimsPrincipal as necessary. Any of the claims that I added this way were later removed when another user of that type logged in. My solution was to change the static properties to KeyValuePairs and create new claims for each user.
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.
I'm reading up on ASP .NET MVC, and I just got to a section talking about the Authorize attribute. It's saying that the Authorize attribute is used to check that a user is authenticated against a Controller. Is this true? I know that the attribute is designed to be used for authorization purposes, but is it also a best practice to use this attribute for authentication?
If not, what is the best practice for verifying (not performing) authentication?
If so, why is it done this way? Am I missing something?
Authorize attribute can be used to check to see whether the user is logged in. It can also be used to check if the user is a member of a specific role and has a specific name.
It essentially does the same thing handled by <authorization> section in web.config when using Web forms.
It doesn't specify the authentication method. It's handled by <authentication> section in web.config just like Web forms.
EDIT (clarification about authentication and authorization):
Authentication is identity verification. That is, you check to see who the user is. This can be performed by checking a user name and password, checking your Windows authentication token, scanning retina, voice identification or whatever else.
Authorization is the act of limiting access to a specific resource to users that satisfy a certain criteria. To be able to authorize a user to a resource, you should know the rights the user have. To check that, you should know who the user is in the first place. So the user have to be authenticated.
Essentially an empty [Authorize] attribute does authorization, not authentication. It doesn't check who you are. It just checks if the one who you verified to be does have access to the resource or not. However, its authorization criteria is "anyone successfully authenticated." You can specify a different criteria. So, indeed it's doing authorization, not authentication.
Authorize does indeed check that the user is authenticated, otherwise it would not be able to determine the roles for the user or which user (other than the anonymous one) the current user is. That is, in order to be authorized, if anonymous access is not allowed, you have to be authenticated first. Below is the relevant snippet from the AuthorizeCore method in the RTM version (from http://www.codeplex.com/aspnet).
// This method must be thread-safe since it is called by the thread-safe OnCacheAuthorization() method.
protected virtual bool AuthorizeCore(HttpContextBase httpContext) {
if (httpContext == null) {
throw new ArgumentNullException("httpContext");
}
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated) {
return false;
}
...
If AuthorizeCore returns false in OnAuthorization, then the AuthorizationContext.Result is set to a new HttpUnauthorizedResult which will result in the user being redirected to the login page (in FormsAuthentication) or an error.
EDIT: After reading your comments to other answers, I would say that you ARE missing the point. Technically it is only doing authorization. One level of authorization, the minimum, is that you need to be authenticated to perform an action. You get this by not specifying any users or roles for the Authorize attribute. Any user or role is allowed, as long as it is authenticated. By specifying users and/or roles that act as filters you narrow down the scope of the action and the user needs not only be authenticated (so you can check the name/role membership), but also qualify based on the filter.
Authentication and Authorization are two different concerns.
Authentication verifies that the user is who he says he is, almost always done in most web apps by verifying that he/she has some knowledge (like a password) that only he/she should know.
Authorization verifies that an authenticated user has the permissions to do something. Only administrators can access admin pages for instance.
Since we can get the roles of a person only once logged in, it is possible to use the Authorize attribute to test for authentication.
Take a look at this blog post and see how the author implements both a custom Authorize and Authentication attribute:
Securing your controller actions
You'll see that the Authorize attribute has to check for authentication, since only authenticated users can have a role.