I have a ASP.NET MVC website.
I don't really manage users, but I do a login to an external API and then I store a "ASPXFORMSAUTH" cookie.
It's a WCF service. In my controller, I call :
MyWcfServiceClient.Login()
In the AfterReceiveReply, I store the response of the service in a variable :
cookie = httpResponse.Headers[HttpResponseHeader.SetCookie];
Then In the controller, I get this cookie and store it using :
Response.Cookies.Add(cookie);
I'm a beginner with ASP.NET MVC, but can I use the [Authorize] attribute to allow the access to the controllers methods only if the request contains this cookie ? And [AllowAnonymous] on the methods before the API login.
EDIT :
So it should work just adding the [Authorize] attribute ?
I'm calling the controller method using ajax, and the value of Request.Headers["Cookie"] is .ASPXAUTH=1D415AF723......
But I get the ajax error callback...
Am I missing something ?
[Authorize] will allow access to authorized users only.
You can either put it at the top of the controller so it applies to all functions on the controller or in front of individual functions. its more powerful than that though as you can allow only specific users or roles. documentation here
The allow [AllowAnonymous] is used when you have added some sort of Authorize to the whole controller but want to allow access for all to a function on the controller. its not required if the controller doesn't have an authorize attribute on it. example here I think the default MVC account in visual studio uses this on the account controller for password rest and login.
I'm not fully sure since I haven't tried it before. But if you set the correct cookies (the default aspx auth cookie) the AuthorizeAttribute should prevent you from reaching the controller if you aren't authorized. Have you tried using the authorize attribute on a controller and logging in using your external API? Because it might just work out of the box.
Another option is to extend the default attribute by making your own. See the following articles for more information about this.
Article from John Galloway
Another question here on SO about extending the Authorize attribute
MSDN Article about the Authorize attribute
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.
In the Session_Start event, it calls an authenticate_authorize class to return an AuthResult object.
public AuthResult
{
public enumAuthResult Result {get;set;}
public string Controller {get;set;}
public string Action {get;set;}
}
If the Result is not enumAuthorized, the controller and action will be returned to the Session_Start. Then if Request.RedirectToRoute() is used to route to the controller's action, the Session_Start will be in an infinite loop. It seems that RedirectToRoute() always restarts the session. Instead, if Request.Redirect() is used then proper controller's action is fired up normally.
What is the right way to call a controller action without using redirect in Session_Start event?
Should I split the authentication and authorization in Application_AuthenticateRequest and Application_AuthorizeRequest events separately?
If the authentication and authorization are done in separate events, how can I pass the AuthResult object to Session_Start event for it to properly redirect or route to the controller?
Response.RedirectToRoute(AuthResult.Controller, AuthResult.Action);
Response.Redirect(string.Format("{0}/{1}",AuthResult.Controller, AuthResult.Action));
What is the right way to call a controller action without using redirect in Session_Start event?
The right way is to use an Authorization Filter, which runs after the action has been selected. Microsoft has included a default implementation, AuthorizeAttribute, which serves most people's needs with users/roles, but can be inherited if you need to make a custom scheme.
AuthorizeAttribute uses the IPrincipal and IUser interfaces, which can be implemented by any custom security scheme and are implemented with ASP.NET membership and ASP.NET identity.
If you attempt to base your security on URLs, it will be nearly impossible to ensure that every route to an action will go through your security scheme. For example, by default the home page can be accessed through /, /Home, or /Home/Index, so if your URL based authorization only accounts for /, the user will be able to circumvent your security and access your home action through /Home or /Home/Index.
I would recommend against creating your own security scheme - to do so requires experience that you don't have based on your question. Instead, you should review the MVC security overview to find the best option for your application and then go through a tutorial that explains how to implement it. Do note that ASP.NET identity supersedes ASP.NET membership.
I have gone through many blog articles describing how to validate users in our web applications using [ValidateAntiForgeryToken] attribute. But this has limitations such as can be used only with HTTPPOST methods. My requirement is I have a MVC 5 application which returning sensitive data (Ex: bank statements) using HTTPGET methods. How to authorize/protect these action methods from anonymous users ?.
I want to write a token based authorization mechanism.
You are correct - the ValidateAntiForgeryToken mitigates against Cross-Site-REquest-Forgery (CSRF). It is specific to POST's, as it can correlate the a response issued by a server, and the HTML posted from a user. There is no concept of CSRF for GETs.
To protect GETS from anonymous users, use the [Authorize] attribute on any methods that you require users to be logged into the websites. If they are not, they will be redirected to the login section, as configured in your web.config.
I have a .Net MVC application. I use Asp.net Identity for login and roles.
Every controller I have is decorated with [Authorize]
I have not done anything else in the code to protect the application.
Is there anything Else that must be done in ordet to protect the site? And im not takling protection of the webserver. Only the website.
Thanks
Add MVC's anti-forgery support, this basically writes a unique value to an HTTP-only cookie and then the same value is written to the form. When the page is submitted, an error is raised if the cookie value doesn't match the form value.
It's important to note that the feature prevents cross site request forgeries.
How to use it:
Decorate every controller action used to post data with this: [ValidateAntiForgeryToken] and add the unique value to your form posting the data by adding the following to your form #Html.AntiForgeryToken()
If I disable anonymous browsing of an MVC site and only allow NTLM authenticate users access, I presume any page simply decorated with the
[Authorize]
attribute will pass, so if I want to only allow user limited access to parts of the site, I'll need to do add them to an AD group and use that to apply the filter?
[Authorize] by default will only look for IsAuthenticated flag. So yes, applying[Authorize] without additional param will allow all logged in users.
To limit, you can use Roles/Group (NOT OUs). It will check the IsInRole (from IPrincipal).