I'm using the MembershipProvider that is part of the MVC2 default project.
I'd like to be able to take a list of user names, and log the users off, and destroy their session if needed. The closest I can seem to come is this:
foreach(string userName in UserNames)
{
MembershipProvider MembershipProvider = new MembershipProvider();
MembershipUser membershipUser = MembershipProvider.GetUser(userName, true);
Session.Abandon();
FormsAuthentication.SignOut();
}
I think I need to use a session and/or signout method related the user I want to log out, but I am unsure where those would be.
What is the proper way to do this?
That won't work...
Session.Abandon() will be for the Current HttpContext. Not for each user like you are trying to do.
Same for FormsAuthentication.SignOut().
Your best bet is check the current user against that array in the Application_AuthenticateRequest Event and sign them out there:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
//add your ckeck here
if (Usernames.Contains(User.Identity.Name))
{
Session.Abandon();
FormsAuthentication.SignOut();
}
}
}
I Didn't use the Membership provider when i did this but basically i saved the SessionId, Username and lastPage visited in a database when the user logged on. Each page then used the current SessionID to get the username and do related username stuff, like display balance for current user etc. if there isn't a valid user for the session then return to log-on page.
This allowed me the see the users progress through the website and manually disconnect whoever i wanted and gave me Single Signon per user . There was also a bunch of clean-up code in the global.asx page
This turned out to not be related so much to the MembershipProvider, but to the FormsService. My final solution turned out to be a sort of hybrid of the two other answers posted here.
I ended up creating my own FormsAuthenticationTicket in the Account controller in the LogOn action. I generate a unique identifier for the user's authenticated session, and save that identifier to the database. I also added the user's ID to the UserData part of the auth ticket for reliable lookup. By default the auth ticket only contained their user name. The FormsAuthenticationTicket is then stored in a cookie upon successful user log on.
Basically all of that replaced the FormsService.SignIn(model.UserName, model.RememberMe);
I also added public void Application_ReleaseRequestState(object sender, EventArgs args) in the Global.asax. I'm not sure if this is considered expanding a function or what, as it does not appear to be an override. Inside of Application_ReleaseRequestState it gets the user's FormsAuthenticationTicket from a cookie. It then decrypts the auth ticket, and gets the user's UserID from the UserData portion of the ticket. Then it asks the database if the auth ticket is still valid. If the ticket is not valid, it sets the user's cookie to expire.
To force users to log off, I can either change their auth ticket expiration dates in the database, or toggle the disable bit for their auth tickets in the database. Either way when Application_ReleaseRequestState asks the database if their auth tickets are valid, they won't be. Thus their cookies will get set to expire upon the next page the user hits after this check was made.
Related
i just want to reset password using mvc 4 c#
FYI: i am using my own custom authentication and authorization ,
i know that the best way is to send link for reset password ,
i just need article or code snippet apply this without membership,
i want to know how to make link expire? and how to generate unique link? and what is token ? and the use of token in rest password?
FYI:when i am build my own authorize system i just override AuthorizeCore function like this
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
}
is there any functions like AuthorizeCore to confirm account or change password can override ?
appreciate help thanks
Splitting up the problem":
Generate a GUID to create a unique link
I like links that are not recognizable by the user; your best candidate is probably a random number or a GUID (http://en.wikipedia.org/wiki/Globally_unique_identifier).
System.Guid.NewGuid().ToString("P"));
Persist the username + expiry time with the GUID
Either in memory or in your database, store the guid, the username and the timeout data. You do not expose this data to the outside
Reset the password
Your user clicks ",,/reset&guid=3432432. You retrieve the data in your database and the username, the timeout to the guid provided and reset the password (or not)
User is logged in and wants to do something major and I want them to re-enter their password so I can make sure that they are the user that is logged in.
How can I confirm that this password is for the account holder?
Would be happy to know how to do it via ASP.NET Identity or how to set up a stored proc to go against the AspNetUsers table or how to do it via Entity Framework.
How can I confirm that this password is for the account holder?
how to do it via ASP.NET Identity
To reverify the password of currently logged in user, provide the user VerifyView to enter password and use the following method to check if the user exists.
var user = await UserManager.FindAsync(User.Identity.Name,VerifyViewModel.Password)
If the user is found, the current request is the same from the account holder.
Membership.ValidateUser is from earlier version of Membership framework, not from ASP.NET Identity.
You can also use UserManager.CheckPassword() extension function:
UserManagerExtensions.CheckPassword Method
string id = User.Identity.GetUserId();
var user = UserManager.FindById(id);
if(!UserManager.CheckPassword(user, model.Password))
{
ModelState.AddModelError("Password", "Incorrect password.");
}
With Identity framework you never want to hit the database directly. Always use the API provided. The database structure has changed several times in the past few years, so introducing dependencies (e.g. on a data context) is adding work for no reason.
For async usage, see the answer already provided by jd4u.
For synchronously identifying that the password matches the current user, you need to first include:
using Microsoft.AspNet.Identity;
as this brings in a number of synchronous extension methods for identity framework.
You can then check with Find on the UserManager like this:
var user = UserManager.Find(User.Identity.Name, password);
if (user != null)
{
// It is them!
}
If the user is not null, then you have a match of password and current username.
You can use UserManager to do that:
if(UserManager.PasswordHasher.VerifyHashedPassword("hashedPassword", "password")
!= PasswordVerificationResult.Failed)
{
// password is correct
}
For more information see the link:
How to check password manually in Asp.Net identity 2?
After checking a user's credentials and confirming they are good, I'm using FormsAuthentication.SetAuthCookie("Username", false); to authenticate the user.
In the masterpage I then use Page.User.Identity.IsAuthenticated to make sure we're dealing with a logged in user and not a guest.
The problem lies in first setting the auth cookie. When I set the auth cookie, immediately afterwards I run a method that uses Page.User.Identity.IsAuthenticated to change the welcome message from a generic "Welcome, guest!" message to a more personal "Welcome, username!" message. This does not work until I go to another page, so I know the login process has worked, but it seems I cannot access the information I need until a refresh or a redirect happens.
Do I need to redirect the user after setting the auth cookie in order use Page.User.Identity.IsAuthenticated to change the message?
I have seen this before so I know the answer is yes. (As in, yes you do need to redirect the user to correctly use Page.User.Identity.IsAuthenticated)
What I imagine is the cause is because IsAuthenticated evaluates the current request, and when the current request first came in it was recorded as not authenticated.
What you will need to do is apply whatever logic you have in said method without the check for IsAuthenicated (make it assume true).
Now I don't know the details of your method as to suggest how to re-factor it to cope with this, but you could split out the "Do Stuff" part into a separate function which you could then call directly from you login function to bypass the authentication check.
EDIT: To back up my assumption you can read this page.
The interesting part:
The forms-authentication ticket supplies forms-authentication
information to the next request made by the browser.
I'd like to point out that there's actually a way around this (since I've never seen this said in any other question like this). You can retrieve the cookie and its data where User.Identity's information comes from without a redirect. The thing is, the cookie just hasn't been sent to the browser yet.
It simply gets the cookie made by FormsAuthentication from the Response.Cookies object:
HttpCookie EncryptedCookie = Response.Cookies.Get(FormsAuthentication.FormsCookieName);
FormsAuthenticationTicket DecryptedCookie;
try {
DecryptedCookie = FormsAuthentication.Decrypt(EncryptedCookie.Value);
} catch (ArgumentException) {
// Not a valid cookie
return false;
}
// DecryptedCookie.Name: The Username
// DecryptedCookie.UserData: Any additional data, as a string. This isn't normally used
return !DecryptedCookie.Expired;
I am using Windows Identity foundation to manage login to our site.
When a user logs in i am using some information in his request to put into the claims.
It is all working fine, but now I need to manage this scenario:
user is already logged in, athenticated and has a valid token.
But user decides to browses in again (via a redirect from another site)
So his information in his request is different.
I want to either
Sign him out - so that he naturally creates a new token with his new information
OR update his existing token.
So my question is:
How do i Sign out of Windows Identity foundation?
Or How do I update the existing claims?
I have tried this code:
public void ExpireClaims(HttpContextBase httpContextBase)
{
var module =
httpContextBase.ApplicationInstance.Modules["WSFederationAuthenticationModule"] as
WSFederationAuthenticationModule;
if (module == null)
{
return;
}
module.SignOut(true);
}
But module is alway null.
and i tried this:
public void FederatedSignOut(string replyUrl)
{
WSFederationAuthenticationModule.FederatedSignOut(null, new Uri(replyUrl));
}
But i get a null reference execption when i do this.
Thanks very much.
Essentially sign-out is just deleting the cookie so:
FormsAuthentication.SignOut
or
FederatedAuthentication.SessionAuthenticationModule.SignOut
or
FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie
will work.
Or use the FederatedPassiveSignInStatus (should be in your Toolbox). Set the property SignOutAction to FederatedSignOut and the control will clear out your STS session as well.
I need to revoke an authentication cookie if the user no longer exists (or some other condition), after the forms authentication mechanism already have received the authentication cookie from the browser and have validated it. I.e. here is the use scenario:
The user have been authenticated, and granted non-expiring auth cookie.
In a few days, the user tries to access my web app again, and as the cookie is valid, the forms authentication mechanism will grant access.
Now I want to perform a second check (whatever condition I want), and decide if I want to let the user continue, or to revoke the authentication.
The question is - is there an official automated way for this? So far I have come with some possibilities, but I do not know which one is better. I can capture the Authenticate event in global.asax, check whatever I want, and to revoke I clear the cookie, and then one of these:
Redirect again to same url - this should work, as this time the forms authentication will fail, and it will redirect to logon page.
Throw some exception ??? which one to make the redirect happen w/o me specifying anything?
Somehow to get the logon page url from the config file (any ideas how/which config handler to use) and redirect directly?
Some FormsAuthentication class/method I have overlooked, which is designed for this?
Any other idea?
I don't think there is an automated way to achive this.
I think the best way would be to add a date to the auth cookie which will be the last time you checked whether the user exists.
So when a user logs-in you'll:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
name, // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMonths(1), // Date/time to expire
true, // "true" for a persistent user cookie
DateTime.Now.ToUniversalTime(), // last time the users was checked
FormsAuthentication.FormsCookiePath);// Path cookie valid for
// Encrypt the cookie using the machine key for secure transport
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName, // Name of auth cookie
hash); // Hashed ticket
cookie.HttpOnly = true;
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
//cookie.Secure = FormsAuthentication.RequireSSL;
Response.Cookies.Add(cookie);
Then everytime a user is authenicated you can check the additional date you passed to the Authentication ticket and in 10 minute intervals or less double check against the database whether the user exists.
The code might look something like this:
public void FormsAuthentication_OnAuthenticate(object sender,
FormsAuthenticationEventArgs args)
{
if (FormsAuthentication.CookiesSupported)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(
Request.Cookies[FormsAuthentication.FormsCookieName].Value);
DateTime lastCheckedTime = DateTime.TryParse(ticket.UserData);
TimeSpan elapsed = DateTime.Now - lastCheckedTime;
if (elapsed.TotalMinutes > 10)//Get 10 from the config
{
//Check if user exists in the database.
if (CheckIfUserIsValid())
{
//Reset the last checked time
// and set the authentication cookie again
}
else
{
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
return;
}
}
}
catch (Exception e)
{
// Decrypt method failed.
}
}
}
}
You can even cache the users that have been deleted the last 10 minutes and check against that collection.
Hope that helps.
If you are rejecting the cookie for some other reason than an expired session, then I think you should redirect the user to a page that describes what they need to do in order to gain access. If logging on again is sufficient, then the logon page would suffice. It sounds, however, like there are conditions under which simply logging on again is not possible. In those cases, it would be better to redirect the user to a suitable error page that describes why they are unable to access the site and explains how to gain access again (if possible).