Is it possible to validate a user's Username + Password without logging them in? I understand a usual login block will look like this:
if (!Page.IsValid)
return;
if (Membership.ValidateUser(UsernameInput.Text, PasswordInput.Text))
{
FormsAuthentication.RedirectFromLoginPage(UsernameInput.Text, false);
}
else { [...] }
With the Membership.ValidateUser() call setting the cookie for the response.
However, there are some additional checks I'd like to perform after the password is confirmed. (Pulling out an expiry date for that user, for example).
Is there a way to do it without just calling FormsAuthentication.SignOut(); after invalidating the page?
I think your assumption that Membership.ValidateUser is setting the cookie is wrong. I don't believe it sets cookies.
FormsAuthentication.RedirectFromLoginPage sets the cookie.
Think about it from a separation of concerns standpoint:
Membership is where you store your users and password, but it really doesn't know anything about the web or cookies.
Forms Authentication is the technology that keeps a user logged into a website but doesn't care how you determine if that user is valid. All it cares about is having a username and setting/reading cookies, so that the user doesn't have to log in with every
request.
Related
I'm building a custom ASP.NET Identity 2.0 implementation that uses our own data model, another ORM, other business logic, etc. By default, a user is logged in by setting the ApplicationCookie, after which the AuthorizeAttribute recognizes the cookie and logs the user in. For our own implementation, I want to add more ways to log in. For example:
Impersonation
Password reset token
Google Authenticator (two-factor)
SMS (two-factor)
In all these scenarios the user must be logged in, but what actions the user is allowed to perform depends on the way he logged in. For example: when the user logged in using a 'password reset token', he may change his password but not do anything else. When the user logged in with 'username + password', he may do basically everything, except for the actions that need a higher permission level (where the two-factor methods come in play). In order to do this, I want to build a custom AuthorizeAttribute that checks what login method was used, and then decides whether the user may perform the action or not.
The problem I'm facing is that I can set other cookies than ApplicationCookie (e.g. the TwoFactorCookie that is being set by going through the SMS process), but those cookies are not recognized as authentication cookies. Thus, when I have a TwoFactorCookie, I can't use that cookie to log in. Only having an ApplicationCookie results in a log in.
The issues I'm struggling with:
Do I always need to use ApplicationCookie to log in or can I use custom cookies to log in as well (so for example I can log in using ApplicationCookie, TwoFactorCookie and XYZCookie?
Should I have different cookies for each authentication method or should I have only 1 cookie and store the authentication method/type in a different way (for example in a Claim)?
If I should use different cookies, should I also write custom authentication middleware for each authentication method/type or can I use the default CookieAuthenticationMiddleware? As far as I know, the only thing that has to be done is set a cookie, and flag it with the correct authentication method so I can see how the user was logged in.
Edit:
As per Hao Kung's suggestion I made a couple of extension methods that look like this:
public static void UseSmsSignInCookie(this IAppBuilder app, TimeSpan expires)
{
if (app == null)
throw new ArgumentNullException("app");
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = ApplicationAuthenticationTypes.Sms,
AuthenticationMode = AuthenticationMode.Passive,
CookieName = CookiePrefix + ApplicationAuthenticationTypes.Sms,
ExpireTimeSpan = expires,
});
}
I try to log someone in by calling AuthenticationManager.SignIn with a custom ClaimsIdentity that has my custom AuthenticationType (SMS). This doesn't work though: after calling SignIn, the result of HttpContext.Current.User.Identity.AuthenticationType still equals ApplicationCookie. The cookie has been set as expected though.
Does anyone have an idea what I'm missing?
So each instance of a CookieMiddleware basically represents one auth cookie, if you want multiple cookies, you can add more than one CookieMiddleware and to retrieve the ClaimsIdentity mapping to your cookie, you just need to call Authenticate on the AuthenticationManager passing in the AuthenticationType for the cookie you want.
I'm using the DropCreateDatabaseAlways Initializer so my database gets destroyed every time I start the application (at least I hope so). The funny thing is I still see myself as logged in. I get pass the Authorize attribute and can do dangerous stuff. This is probably because of leftover cookies from previous testing.
Registration/login part of my app is the MVC 4 Internet Application template untouched. Shouldn't ASP.NET check the cookie values against users saved in the DB? WebSecurity.IsAuthenticated returns true and WebSecurity.CurrentUserName returns the name.
The only thing working as expected is WebSecurity.CurrentUserId which returns -1. I'm a newbie so I can only guess this is because UserId isn't stored in the cookie and must be retrieved from the database.
Am I right? If so, does it mean I should always use WebSecurity.CurrentUserId to determine whether a user is logged in? WebSecurity.IsAuthenticated and User.Identity.IsAuthenticated seem pretty useless in that case. I can delete a user's account and he or she remains unaffected. What should be done differently if I am wrong?
If you want to realiably check whether a user has not been deleted, you just have to consult the database.
Note that users and administrators work concurrently. This means that a user can be deleted just a second after he has been authenticated. A cookie can be then even one or two seconds old (!) and the user could probably have been just deleted.
In a most pessimistic scenario, a user types a valid username and password and is succesfully logged in and get the "sorry, your account has been deleted" just one request later (because the account has really just been deleted).
There will be a small window where if a user is deleted and they are still logged in that they can still access the site. Since most actions require a validate user id, you can simply throw an excpetion and log the user out.
Normally the database does not get blown away on each build, so I'm guessing this is not a use case SimpleMembership was coded for. You can of course check for this. I'll make another assumption that you are not closing your browser when you rebuild the site and deploy the new database. In a real world scenario these things just don't happen. The database is never blown away and the user id is never lost.
Generally once you've logged in the user, the user is not authenticated anytime after that (unless they have logged out, or the session has expired). That's the point of login. The authentication cookie is an indication that the authentication happened and was successful. The assumption going forward is the user has access to your site and is not reauthenticated.
As long as the authentication session remains open (i.e. browser now closed), the session cookie remains active and MVC assumes that the user is still valid.
Remove the cookie by using FormsAuthentication.LogOff() if the user is authenticated (User.Identity.IsAuthenticated == true) and there's no valid user in UserTable (WebSecurity.CurrentUserId == -1).
I had the same issue, but solved it by specifying the required role(s) in the Authorize attribute. As soon as you do this, it start getting to the database and fails with the "user does not exist" error, which is what you want.
[Authorize(Roles = "Customer")]
public class DashboardController : Controller
In normal case adding Session.Abandon(); to to your LogOff action in AccountController would do the job of clearing session:
public ActionResult LogOff()
{
FormsAuthentication.SignOut();
Session.Abandon();
return RedirectToAction("Index", "Home");
}
So I think you can try adding Session.Abandon(); in init code, where you use DropCreateDatabaseAlways to clear session each time.
The ticket issuing time is usually encrypted within the authentication cookie then you can use it to require re-authentication to sensitive areas (inbox/billing etc.) if more than X time passed since login.
If you insist on invalidating all current auth tickets upon application changes (i.e database/configuration) you can change this settings in your web.config:
<machineKey validationKey="..." decryptionKey="" />
how to auto login the user like in facebook.
what i mean that if the user ticks remember me then next time he will be auto logged in
thanks
How websites like Facebook do it is by storing a cookie on the users computers/browser. Which stays there until it is deleted or expires. When the user then visits the Website your code will read the data from the cookie and authenticate based on that information. You could be storing a Token for example which you save to a database so your can see that it represents the user, this is just a idea. Just to be safe you should maybe also consider encrypting the data in the Cookies. Be careful about just reading Cookie's, they are easy to change and can give you some serious security problems.
So it depends if your rolling your own custom authentication, in which case you need to create the cookie and check for it. Or if your using ASP.NET FORMS for authentication in which case you can look here - How to get the asp.net login control to auto authenticate a previously authenticated user?
Use a persistent cookie (or HTML5 local storage like Stack Overflow does) to store some reference so that you know who has authenticated in your back end.
You need to set a cookie when the user logs in and set its expiration time in the future. Until the time elapses, your application would recognize the user.
I'm making the assumption you'll be using Forms Authentication.
If so, take a look at the System.Web.Security.FormsAuthentication class.
Specifically - these two static methods:
bool Authenticate(string username, string password)
void SetAuthCookie(string username, bool createPersistentCookie)
Setting the createPersistentCookie to true will persist the session cookie across browser sessions.
I'm trying to get forms authentication working for an mvc site. I have a custom database with a users table, and I would like to do my own password validation.
I am logging in my user like this:
if (PasswordHasher.Hash(password) == dataUser.Password)
{
FormsAuthentication.SetAuthCookie(email, true);
return true;
}
The problem is, when the session expires obviously the user has to login again.
I am thinking I should be storing this Auth cookie in my users table?
Update: I'm obviously in desperate need of more education in this area. I just noticed that the user stays authenticated even after an iisreset.
I guess what I'm asking is how can I get persistent and non persistent authentication working properly. I want a user to not have to login again if they click "remember", and if they don't then their authentication should expire when the forms authentication is set to expire.
Turns out I forgot to put my variable in the second argument of the SetAuthCookie method. It was always sending true for the "persistent" argument. FML.
I'd recommend implementing a custom Membership Provider so you can leverage the existing controls or patterns that are out there for the existing membership providers.
Am trying to design login page for my website and I am looking for methods other than forms authentication. The way in which I am trying is to have a table in the database that stores user information and check for the user validity.
The point where I get struck is how do i set cookies and session variables and how will I carry it through out the system. Can anyone tell/suggest me where I can relevant material so as to move forward. And also is my idea of negating traditional forms authentication and going for a model I described, is it good also does any other better method exist?
You can do this even with forms authentication itself...
For Forms Authentication to work, you need not have to use the Complete Database Setup that MS uses to Authenticate. You can simply have your own Database and Validate a user yourself, and just set the cookie.
String UserName = "CoolGuy";
String PassWord = "Pwd"
Boolean isValidUser = YourClass.YourMethod(UserName, PassWord);
if (isValidUser)
{ FormsAuthentication.setAuthCookie(UserName, false); }
This will authenticate the user "CoolGuy" for the session, provided YourMethod returns true. And you need to put this code only in Login Page... and the user will automatically be authenticated for the entire session or whatever...
Please see my response to another similar question here... ASP.NET access controls