What is the best way to set up authentication against a custom database of users, in ASP.NET? My current setup is not great, and I am sure that there is a better way to do authentication, but all I can find are some articles that are seven or eight years old. My current setup is as follows:
Application uses the Windows username (via Windows Authentication), to work out whether a user is in a database of allowed users. This is done via a call to an Authenticate method in Page_Load.
If the user isn't in the allowed users, then the page redirects to a login screen.
The flaw with this method is that it calls:
Response.Redirect("~/login.aspx", false)
Which executes the entire body of the Page_load method. Is there a better way of doing authentication? Would something like custom Page classes, or HTTPModules do the job?
You could do your check earlier in the request, like in OnInit, or you could do something a little more robust, like implement your own membership provider: MSDN article / Video tutorial
Okay, so this is basically how I done it. I wrote this class that inherits from System.Web.UI.Page. I override the OnInit event and this is where the authentication happens (looks up the Windows username against the database of users). If the user doesn't get authenticated, isTerminating gets set to true, and the OnLoad event only runs if isTerminating is false. I tried leaving a Response.Redirect with the second parameter set to false on its own, but this still ran all the subsequent page events. (even with a call to HttpApplication.CompleteRequest())
public class BasePageClass : Page
{
private bool isTerminating = false;
protected override void OnInit(EventArgs e)
{
isTerminating = !AuthenticationManager.Authenticate();
base.OnInit(e);
}
protected override void OnLoad(EventArgs e)
{
if (!isTerminating)
{
base.OnLoad(e);
}
}
}
I have no idea whether not running the OnLoad event is the best thing to do, but it "seems" to work fine.
Related
I created a new asp.net web application using the template that visual studio has. That type of project create a login out-of-the-box which I configured with the aspnet_regsql command to work with my database.
Now, when someone logs into the application, I need to know whether or not the login was sucessful, so I can save in Session[''] the user name among other things.
I was expecting to find a method that returns true or false but instead in the Login.aspx.cs is just the Page_Load method and I don't understand how it works.
I tried associated a onclick method that get the value of the UserName control, but obviously, that only works when the user log in for the first time, if the user check "Remember me next time" it won't work.
The AuthenticateRequest event is raised when the user has been authenticated, however in this event you do not have access to the SessionState yet. Therefore, to save the Session you should consider the PostAcquireRequestState application event.
ASP.NET Application Life Cycle Overview for IIS 7.0
ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0
For additional info:
AuthenticateRequest event
Example:
In global.asax
void Application_PostAcquireRequestState(object sender, EventArgs e)
{
if (Context.Session != null)
{
Application.Lock();
Session["user"] = User.Identity.Name;
Application.UnLock();
}
}
Additionally, if you are using the LoginControl, you can handle the LoggedIn event:
ASPX
<asp:Login runat="server" ID="login" DestinationPageUrl="~/Default.aspx"
FailureAction="RedirectToLoginPage"
onloggedin="login_LoggedIn" ...>
....
ASPX code behind
protected void login_LoggedIn(object sender, EventArgs e)
{
// set the Session here
}
The aspx web project template makes use of the asp:Login control, which does the authentication for you.
If you need to customize the login, you can roll your own username / password inputs, and then call the membership API directly, e.g.
if (Membership.ValidateUser(username, password))
{
FormsAuthentication.SetAuthCookie(username, rememberMe);
// Do your custom stuff here
...
You can also check to see whether the user is authenticated by using
UserPrincipal.Identity.IsAuthenticated
See MSDN for more details
I need to implement CSRF(Cross Site Request Forgery) Guard in my code (asp.net).
Though I got a library from OWASP, implementing it is a pain since no documentation is given. Can someone provide me an easier way to implement csrf guard in .net, or configure OWASP library correctly ?
Thanks
-Chandan
ASP.NET MVC
If you're using asp.net mvc you can use the anti-forgery token. Basically in your view you would place the following code:
#Html.AntiForgeryToken()
And on your controller you would put this attribute at the top of the controller:
[ValidateAntiForgeryToken]
public ActionResult Foo()
{
// Foo code
}
What this does is ensures that the user cannot submit the form from a remote site, because they are unable to generate the token. You can also create a token with a salt.
ASP.NET WebForms
For asp.net Webforms you can override the OnInit method and set the ViewStateUserKey to the the session id. Web forms will validate the viewstate with a MAC check thereby acting like an anti forgery token. Because an attacker cannot generate a valid viewstate (since they don't have the ability to generate a valid MAC because they can't put the session id in the viewstate) the MAC will fail. You will have to do this on each page, or create a base class that already overrides oninit and does this.
public partial class Default : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.ViewStateUserKey = Session.SessionID;
}
}
I'm securing an ASP.NET MVC 2 application, and I have a user who is in the role "Foo".
This is true:
User.IsInRole("Foo")
But yet, when I attempt to lock down a controller action like the following, the user is denied:
[Authorize(Roles = "Foo")]
public ActionResult PrivatePage()
{
return View();
}
If IsInRole reports true, why would the Authorize attribute not allow the user in?
It could be caused if you are storing persistent cookies for your forms authentication cookie. In that scenario IsInRole may check against the cookie without verifying up to date login.
For future people with a similar problem - it could depend on how you are actually setting up your roles on the current user.
I had a similar issue where the roles were being pulled out of the cookie in an override of OnActionExecuting in a base controller. Turns out this was executing after the [Authorize] attribute, so the roles weren't actually set up when the attribute was checking for them. The call to User.IsInRole, being in the View, was executing after OnActionExecuting, so it saw the roles fine.
So User.IsInRole returned what I expected, but the [Authorize] attribute did not.
I was able to resolve this by moving the code for getting the roles into a more sensible place, that executes before the Authorize attribute - for example, in Global.asax.cs:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
// do stuff in here
}
Or even better, in your own custom attribute - see https://stackoverflow.com/a/5314736/206297.
They should both return true. Have you tried using SQL Profiler to check the queries run against the DB?
I am experimenting with FormsAuthentication (using ASP.NET MVC2) and it is working fairly well.
However, one case I can't work out how to deal with is validating the user identity on the server to ensure it is still valid from the server's perspective.
eg.
User logs in ... gets a cookie/ticket
Out of band the user is deleted on the server side
User makes a new request to the server. HttpContext.User.Identity.Name is set to the deleted user.
I can detect this fine, but what is the correct way to handle it? Calling FormsAuthentication.SignOut in the OnAuthorization on OnActionExecuting events is too late to affect the current request.
Alternatively I would like to be able to calls FormsAuthentication.InvalidateUser(...) when the user is deleted (or database recreated) to invalidate all tickets for a given (or all) users. But I can't find an API to do this.
In the global.asax, add an handler for AuthenticateRequest. In this method, the forms authentication has already taken place and you're free to modify the current principal before anything else happens.
protected void Application_AuthenticateRequest(object sender, EventArgs e) {
IPrincipal principal = HttpContext.Current.User;
if (!UserStillValid(principal)) {
IPrincipal anonymousPrincipal = new GenericPrincipal(new GenericIdentity(String.Empty), null);
Thread.CurrentPrincipal = anonymousPrincipal;
HttpContext.Current.User = anonymousPrincipal;
}
}
Just implement the UserStillValid method and you're done. It's also a good place to swap the generic principal with a custom one if you need to.
I made really basic facebook application, which collect permission from user to post data. Some time ago (around New year) it worked fine.
I am using http://facebooktoolkit.codeplex.com, and my code looks like this:
public partial class Facebook : CanvasFBMLBasePage
{
protected void Page_Load(object sender, EventArgs e)
{
if(this.Api.Users.HasAppPermission(global::Facebook.Schema.Enums.ExtendedPermissions.publish_stream))
And at this moment I am having exception: parameter uid or session key required
As i understand, I should have some session defined by Facebook and CanvasFBMLBasePage should parse it, and make it possible to use application, but this is not happening.
My application settings (maybe I mis something):
Canvas Callback URL: http://www.domain.com/app/action/facebook.aspx?
Render Method: FBML
Also, I put my IP in server whitelist.
Thanks for help
Have you called the "ConnectToFacebook" method in the api before calling "HasAppPermission"?