I'm having a lot of problems with FormsAuthentication and as as potential work around I'm thinking about storing the login in the Session?
Login:
Session["Auth.ClientId"] = clientId;
IsAuthenticated:
Session["Auth.ClientId"] != null;
Logout;
Session["Auth.ClientId"] == null;
I'm not really using most of the bells and whistles of FormsAuthentication anyway. Is this a bad idea?
I would not store any valuable information in the session.
For authentication I would use:
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// Then u use
// this.User.Identity.Name as my membership_id so i could call this everywhere
}else
{
//Redirect to Login
//gettting my LoginPageAddress
Response.Redirect(ConfigurationSettings.AppSettings["LoginPage"]);
}
Login is something like this:
FormsAuthentication.SetAuthCookie(membership_ID, false)
Anyway hope this helps
i don't think it's an bad idea, i've seen plenty of sites using session together with a db to store auth data, however there are other ways to get around not using the formsauthentication tables but still be able to use things like roles.
How do I create a custom membership provider for ASP.NET MVC 2?
has good examples of that.
Related
I am wondering how I add user impersonation on mvc identity 2.0, I seen some people using this:
FormsAuthentication.SignOut();
FormsAuthentication.SetAuthCookie(user.UserName, false);
This wont work for me it wont even sign out I use :
AuthenticationManager.SignOut()
So how do I go along doing this I have admin panel what lists users, I get the userId or userName, what exactly do I have to do? I have never used Claims so I dont understand it much I wont need to revert back to user they can just logout for now.
Here is the solution for anyone who else is having this issue - :
var user = _db.AspNetUsers.Single(a => a.Id == id);
var impersonatedUser = UserManager.FindByName(user.Email);
var impersonatedIdentity = UserManager.CreateIdentity(impersonatedUser, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = false }, impersonatedIdentity);
Thanks for this question as it helped me find a number of solutions including yours and #trailmax. After some thought I went about this a different way, as I just needed to change some of the Claims to do the impersonation. I call this semi-impersonation, as it just changes a few things rather than totally change the user.
Like trailmax I have written a blog post on my approach with all the code. Below I have summarised how it works.
I add a session cookie with the impersonation information I needed to change in the current user to allow them to access information belonging to another user. I my case I had a key to some data.
I then use the new MVC's 5 AuthenticationFilter OnAuthentication method to a) look for the impersonation cookie. If it found it then it changed the Claims in the current ClaimsPrincipal, which the filter would then propagate through the application.
Coming out of impersonation mode was achieved by deleting the cookie, which you do by setting its expire date to a date prior to now.
The benefits are much more control over the level of access, but it won't work in all cases. In my article I compare my approach with #trailmax's approach to bring out the benefits of each implementation.
I'm using asp.net Membership, I develop an admin page who can regenerate a temp password to send to the user, then when the user log on for first time, the password must be changed, but I cant figure out who to know if the password was reseted.
I tried something like in a base controller:
if (user.LastPasswordChangedDate >= user.LastLoginDate)
{
filterContext.Result = RedirectToAction("ChangePassword", "Account");
}
But, I already have updated the LastLoginDate because the ChangePassword Action need to be with a autenticated user.
I was thinking when reseting the password to lock/unlock the user to get updated the "LastLockoutDate" and do:
if (user.LastPasswordChangedDate >= user.LastLockoutDate)
{
filterContext.Result = RedirectToAction("ChangePassword", "Account");
}
But, I can't find a method to do manual lockout
Thanks!!!
There's a lot of things you could do, some would depend on how your system works. For instance, you could store a specific piece of data in the Comment field, if you're not using comments.
Or, if you don't use the "Approved" bit (that is, when you create new users you do not require them to validate an email or something, but instead create them with IsApproved set to true) then you can set IsApproved to False and force a password change if it's false.
There is no method to access much of this data in the Membership API, you just have to access it from you database.
You could also store this in the Personalization provider.
Another option is to simply avoid storing this in the Membership database, and instead just add a table or a field in your apps data to deal with this.
In my asp.net application admin functionality, I am trying to combine AD authentication and form authorization for creating the users, roles and Assign users to roles etc. I have configured MembershipADProvider and AspNetSqlMembershipProvider in my web.config with MembershipADProvider as the default one. After user logs in using AD authentication, I need to switch/assign my membership object to use AspNetSqlMembershipProvider in order to get all the users from membership object (from dbo.aspnet_Users table). How do I switch the provider during run time? I have tried different approaches after searching for this issue and none of that seem to work for me so far.
Here are couple of approaches I tried:
1. foreach (MembershipProvider mp in Membership.Providers)
{
if (mp.Name == "MembershipADProvider")
{
Membership.Providers.Remove(MembershipADProvider");
MembershipUserCollection users = Membership.GetAllUsers();
ddlUsers.DataSource = users;
ddlUsers.DataBind();
break;
}
}
Membership.Providers.Remove(MembershipADProvider"); - doesn't work as it's not supported..
Also, tried to clear the Membership.Providers and then add only the type of AspNetSqlMembershipProvider which are also not supported.
I can't set Membership.Provider with value from
Membership.Providers["AspNetSqlMembershipProvider"] as Membership.Provider is a read only property.
I tried to swtich the connection string between 2 providers, which didn't swtich the provider, as both are different types of providers..if both were sqlserver providers this would have worked I believe.
Please let me know if anybody has successfully implemented or if at all this is a plausible approach. Thank You!
You would pass an explicit provider to your code, rather than taking a dependency on Memebership directly (which just wraps the one flagged as default in the config). There is no need to swap them in and out at runtime, think how this would affect thread safety.
So rather than saying Membership.GetAllUsers(); you would do something like (I don't have a compiler to hand):
public UserSerivce : IUserService
{
private MembershipProvider provider;
public UserService(MembershipProvider provider)
{
this.provider = provider;
}
public IEnumerable<MembershipUser> GetUsers()
{
return provider.GetAllUsers();
}
public void DoSomethingElseUseful()
{
...
}
}
And then to use it for a particular provider:
var service = new UserService(Membership.Providers["mySqlMembershipProvider"]);
var users = service.GetUsers();
Or if using AD specific code:
var service = new UserService(Membership.Providers["myADMembershipProvider"]);
var users = service.GetUsers();
Using DI in this way also helps keep code testable.
If all you need a list of users in the aspnet_Users table, just connect to your database with System.Data.SqlClient objects and query the table. There is no reason (that you mentioned) you need to use a membership provider to get that data.
Having said that, your membership/authentication scheme sounds like it may have some design issues, perhaps best tackled in a different question, but I think it might be useful to you if you sought comment on what you are trying to accomplish overall with the multiple membership providers.
Edit: I found some potentially useful posts on using multiple membership providers. It looks like the general idea is to implement custom code handling the Login.Authenticate event on your Login control, and use Membership.Providers["ProviderName"].ValidateUser to attempt authentication with each provider.
http://www.stevideter.com/2008/03/20/using-two-membership-providers-for-aspnet-logins/
http://forums.asp.net/p/1112089/1714276.aspx
I want to use cookies for storing userId during the session which lets to avoid unnecessary roundtrips to the data base. This userId is used to access some user specific information. As cookies can be easily edited I'm now conserned with the security issue.
In order to forbid an logged in user to edit their userId and so get access to other users' information I use a pretty straightforward method. I add one more cookie at the userId cookie creation moment which stores a hashed value for it. While hashing I use a hard coded 64 byte key. When retrieving the userId from the cookie it is always checked if it matches with its hashed value.
Here is basically my code:
public static int GetUserId(Page page)
{
int userId;
if (page.Request.Cookies["userId"] != null && page.Request.Cookies["userIdHashed"] != null)
{
string userIdHashed = page.Request.Cookies["userIdHashed"].Value;
string userIdCoockie = page.Request.Cookies["userId"].Value;
string coockie = (userIdCoockie + "945AFF2FD0F1D89B4B1DBEB1B0C5D3B8B5DCE000AAEA331EB0C3F3A68C3865EFA73BC6EBF30C8DF1AD6B9ECB7094DA5B0C1AF36B5BBD096E3D873E9589E3F664").GetHashCode().ToString();
if (userIdHashed == coockie)
{
userId = Int32.Parse(userIdCoockie);
}
else
{
throw new Exception("UserId does not match!");
}
}
else
{
userId = ...//here userId is being retrieved from the data base and than:
page.Response.Cookies["userId"].Value = userId.ToString();
page.Response.Cookies["userId"].HttpOnly = true;
string userIdHashed = (userId.ToString() + "945AFF2FD0F1D89B4B1DBEB1B0C5D3B8B5DCE000AAEA331EB0C3F3A68C3865EFA73BC6EBF30C8DF1AD6B9ECB7094DA5B0C1AF36B5BBD096E3D873E9589E3F664").GetHashCode().ToString();
page.Response.Cookies["userIdHashed"].Value = userIdHashed;
page.Response.Cookies["userIdHashed"].HttpOnly = true;
}
return userId;
}
So my questions are:
Can such an approach be considered
reliable enough in this situation?
If not should I modify it and how or
should I look for something different
(e.g. encryption/decryption via
System.Security.Cryptography as
recommended here)?
And additional question: Does it really make sense to set HttpCookie.HttpOnly = true to prevent javascript from accessing the cookie given that it can also easily be modified by the user?
UPDATE
Great thanks for answers to Kerrek SB and Darin Dimitrov who share the opinion that it does not make sense to try to protect cookies on my own taking into account that there are already built in protected mechanisms of storing of such kind of information between postbacks.
Options suggested are:
Using the ASP.NET cache (but I believe it is generally supposed to
store information which should be shared between users, so I look at
other two options).
Adding a custom string with userId into UserData part of the
FormsAuthenticationTicket.
Using the Session State.
So currently I'm deciding between the latter two.
Changing the FormsAuthenticationTicket is not really straightforward. Additionally it does not work with the Cookieless Forms Authentication (as stated here).
Using the Session State is much easier but it can affect the performance because it stores the values in the server memory. However may be in my case it is not so dramatic because we store only userId of type int.
So for now the last option looks much better for me. However I would greatly appreciate if anybody else could comment and support or criticise any of options discussed.
Thanks in advance!
You seem to be reinventing some wheels here. While this could be acceptable when doing some standard code, when security is involved this almost always leads to catastrophic consequences.
To track actively logged in user I would recommend you using forms authentication (and here's another useful tutorial). It uses authentication cookies to track users. Those cookies are securely encrypted by the framework so that they cannot be modified using the <machineKey> section of the server machine.config file.
Form your code all you need to do to access the currently logged in user name is the following:
public static string GetUserId(HttpContextBase context)
{
if (context == null || !context.User.Identity.IsAuthenticated)
{
return null;
}
return context.User.Identity.Name;
}
You really shouldn't be handling all this stuff manually especially when the ASP.NET framework has a built-in mechanism for it.
That's terribly roundabout and obscure. If you already have an active session, why don't you just store this kind of data (which the client never needs to know, mind you) in your server-side session data?
All you should ever need to exchange with the client is the session ID, really.
you can also encrypt the cookies with Secure Socket Layer
HttpCookie cookie = new HttpCookie();
cookie.Secure = true;
When a user log into my asp.net site I use the following code:
FormsAuthentication.RedirectFromLoginPage(userid, false);
As I often need to use the userid I can then later get the userid by:
string userid = System.Web.HttpContext.Current.User.Identity.Name;
Now I also want to show the logged in username on each page and my questions is therefore where do I place the username best if I need to use it on every page. User.Identity.Name is already taken by the userid so I can't use that one. Another solution would be to get the username from the database on each page, but that seems like a bad solution.
So: Is the best way to use Sessions to store the username?
There are essentially 6 different ways to store information, each with it's own benefits and drawbacks.
Class member variables. These are only good for the life of one page refresh.
HttpContext variables. Like class member variables, only good for one page refresh.
ViewState, these are passed from page to page to keep state, but increase the size of the downloaded data. Also, not good for sensitive information as it can be decoded.
Cookies. Sent on each page request. Also not good for sensitive information, even encrypted.
Session. Not passed to the end user, so good for sensitive information, but it increases the resource usage of the page, so minimizing usage for busy sites is important.
Authentication Cookie User Data - This is like like cookies, but can be decoded with the authentication data and used to create a custom IIdentity provider that implements your desired Identity information, such as Name or other profile information. The size is limited, however.
You can store just about anything in SessionState in asp.net. Just be careful and store the right things in the right places (you can also use ViewState to store variables.
Check this out for how to use SessionState to store and retrieve variables across postbacks.
public string currentUser
{
get { return Session["currentUser"] as string; }
private set { Session["currentUser"] = value; }
}
Using sessions isn't a bad idea but make sure to check for NULL when retrieving the values for when the sessions time out.
Or you could pass the variable through in the URL e.g
/Set
Response.Redirect("Webform2.aspx?Username=" + this.txtUsername.Text);
/Read
this.txtBox1.Text = Request.QueryString["Username"];