Simplemembership and cookie userdata compatibillity - c#

I am trying to use SimpleMembershipProvider for FormsAuthentication. Now this provider internally creates a FormsAuth cookie without any additional userdata.
I want to include some other information in the cookie such as UserId, Role, etc
I have implemented following-
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (isAuthorized)
{
var formsCookie = httpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
var identity = new AppUserIdentity(string.Empty, true);
if (formsCookie != null)
{
var cookieValue = FormsAuthentication.Decrypt(formsCookie.Value);
if (cookieValue != null && !string.IsNullOrEmpty(cookieValue.UserData))
{
var cookieData = SerializerXml.Deserialize<UserNonSensitiveData>(cookieValue.UserData);
identity = new AppUserIdentity(cookieValue.Name, cookieData.UserId, true);
}
else if (cookieValue != null)
{
//TODO: Find out technique to get userid value here
identity = new AppUserIdentity(cookieValue.Name, null, true);
}
}
var principal = new AppUserPrincipal(identity);
httpContext.User = Thread.CurrentPrincipal = principal;
}
return isAuthorized;
}
}
This attribute is decorated on all required controller methods. When a user registers or login on the website I am updating the cookie as well with additional userdata (serialized string)
var newticket = new FormsAuthenticationTicket(ticket.Version,
ticket.Name,
ticket.IssueDate,
ticket.Expiration,
ticket.IsPersistent,
userdata,
ticket.CookiePath);
// Encrypt the ticket and store it in the cookie
cookie.Value = FormsAuthentication.Encrypt(newticket);
cookie.Expires = newticket.Expiration.AddHours(24);
Response.Cookies.Set(cookie);
However, in MyAuthorizeAttribute it never gets userdata in the cookie. Is there anything wrong in the above code? Or something missing somewhere else?

Found the answer to this question,
check out the link
http://www.codetails.com/2013/05/25/using-claims-identity-with-simplemembership-in-asp-net-mvc/

Related

User authentication Failed

I have created a Website in ASP.Net MVC5 and used a login function in it, it works fine on localhost but when I uploaded the site server,
Server redirects me to the login page on each click.
Below is login Function
public ActionResult DoLogin(string username, string password)
{
if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
{
var user = new UserRepository().GetAll()
.Where(u => u.UserName.ToUpper() == username.Trim().ToUpper()
&& u.Password == password).SingleOrDefault();
if (user != null)
{
FormsAuthentication.SetAuthCookie(user.UserName,true);
var authTicket = new FormsAuthenticationTicket(1, user.UserName, DateTime.Now, DateTime.Now.AddHours(24), true, user.Roles);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Response.Cookies.Add(authCookie);
Session["Name"] = user.Name;
return RedirectToAction("Index", "Student");
}
}
ViewBag.ErrorMessage = "User Name or Password is incorrect";
return View("Login");
}
then I added the below function in Global.asax.cs File.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (authTicket != null && !authTicket.Expired)
{
var roles = authTicket.UserData.Split(',');
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(authTicket), roles);
}
}
}
After that I have added [Authorize(Roles = "Admin")] before each Controller (Not before methods in Controller) I want to Restrict access to.
Now, whenever I login, It redirects me to Index Method of Student controller, after that I click on some other link it again takes me to the Login page. Sometimes it takes me to clicked link without taking me to Login Page. Whats the Problem with my code? it works fine on localhost.
You are assigning the auth ticket twice;
if (user != null)
{
//FormsAuthentication.SetAuthCookie(user.UserName,true); Remove it
var authTicket = new FormsAuthenticationTicket(1, user.UserName, DateTime.Now, DateTime.Now.AddHours(24), true, user.Roles);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Response.Cookies.Add(authCookie);
Session["Name"] = user.Name;
return RedirectToAction("Index", "Student");
}
Also, I suggest you to don't store the roles in cookie because if the user role has been removed or added new one, you can't update them. So,
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (authTicket != null && !authTicket.Expired)
{
var roles = authTicket.UserData.Split(',');//fill it from database and it could be better to use cache mechanism for performance concern
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(authTicket), roles);
}
}
}

Renew FormsAuthenticationTicket UserData

On my login page the FormsAuthenticationTicket is set as a persistent cookie with some custom userdata. Now I need to change this custom user data, so it contains one more parameter. When a previously logged in user visit the site the next time, I deserialize this custom userdata in Application_PostAuthenticateRequest but now I won't contain the newly added paramter.
Can I retrieve this paramter, without the user is required to login once again?
And if not, how to tell to the persistent cookie that it needs to be 'updated'?
Cookie set. userId is a new parameter:
CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
serializeModel.FirstName = model.UserName;
serializeModel.userId = model.userId;
JavaScriptSerializer serializer = new JavaScriptSerializer();
string userData = serializer.Serialize(serializeModel);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
model.UserName,
DateTime.Now,
DateTime.Now.AddYears(5),
model.RememberMe,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
faCookie.Expires = authTicket.Expiration;
Response.Cookies.Add(faCookie);
return RedirectToAction("Index", "Home");
Cookie retrieval. Userid is the new paramter, and is null for previous logged in users:
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
JavaScriptSerializer serializer = new JavaScriptSerializer();
CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
newUser.FirstName = serializeModel.FirstName;
newUser.userId = serializeModel.userId;
HttpContext.Current.User = newUser;
}
Are you using web forms or MVC?
It looks like your setting your HttpContext.Current.User correctly. The problem may be that your by default that your controllers / views still thinks its IPrincipal and not your Custom Principal, So you can't access the new data you set.
You can cast it, or set it in a base controller like below.
// in some controller action
var firstName = ((CustomPrincipal)User).FirstName
[Authorize]
public class BaseController : Controller
{
protected virtual new CustomPrincipal User
{
get { return HttpContext.User as CustomPrincipal; }
}
}

Roles for GenericPrincipal are being lost

I am attempting to set up roles on my dynamic data website, but am encountering an issue.
Between the time I set up by Generic Principal, and when the default page is hit the roles of my principal are lost. The principal is still listed as the context.user, for when I debug my session and inspect the context.user object the user I set up is the user I set up; but all roles related to that user seem to be lost.
This is how I am going about it.
Login page
public partial class Login : System.Web.UI.Page
{
string[] masterServiceResult;
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (IsAuthenticUser(login_email.Text, login_password.Text))
{
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, masterServiceResult[0], DateTime.Now, DateTime.Now.AddMinutes(30), false, masterServiceResult[2], FormsAuthentication.FormsCookiePath);
string encryptedCookie = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedCookie);
Response.Cookies.Add(cookie);
Response.Redirect(FormsAuthentication.GetRedirectUrl(masterServiceResult[0], true));
}
}
private bool IsAuthenticUser(string email, string password)
{
MembershipService membershipService = new MembershipService();
var result = membershipService.GetUserAndRoleFromCredentials(email, password);
//result is an array with userName, userId, error(bool) as string, and error message if any
if (bool.Parse(result[3]) == false)
{
masterServiceResult = result;
return true;
}
return false;
}
}
Then in Global.asax I have attached to the AuthenticateRequest event
void Global_AuthenticateRequest(object sender, EventArgs e)
{
if (Request.IsAuthenticated)
SetupRoles();
}
private void SetupRoles()
{
if (Context.User != null)
{
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (authCookie == null)
return;
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] roles = authTicket.UserData.Split(new char[] { '|' });
IIdentity fi = Context.User.Identity;
IPrincipal pi = new GenericPrincipal(fi, roles);
Context.User = pi;
//sets the application principal to use the logged on user account
System.Threading.Thread.CurrentPrincipal = System.Web.HttpContext.Current.User;
// sanity check to ensure the role was set up.
if (User.IsInRole("Admin"))
{
int i = 0; // debug line
}
}
}
At this point everything is working as intended; my test account is now set as the context.user, the Current Principal user is set as the current user, and the users role of Admin is causing the "int i=0" debug line to be hit. However once the default page Page_Load is hit this is no longer the case.
Default page. Updated 01/03/12 to show another test case.
protected void Page_Load(object sender, EventArgs e)
{
System.Collections.IList visibleTables = MetaModel.Default.VisibleTables;
// this line comes back as false, though at this point the user name is the same.
if (User.IsInRole("Admin"))
{
int i = 0;
}
// the next 4 lines of code is a work around I can do to retrieve the roles from the ticket.
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
// this line of code will correctly show the users role
string[] roles = authTicket.UserData.Split(new char[] { '|' });
foreach (var table in MetaModel.Default.Tables)
{
var permissions = ((MetaTable)table).GetTablePermissions(roles);
if (permissions.Contains(TablePermissionsAttribute.Permissions.DenyRead))
visibleTables.Remove(table);
}
if (visibleTables.Count == 0)
{
throw new InvalidOperationException("There are no accessible tables. Make sure that at least one data model is registered in Global.asax and scaffolding is enabled or implement custom pages.");
}
Menu1.DataSource = visibleTables;
Menu1.DataBind();
}
*Updated: I am a able to get the roles for the user rom the authentication ticket, and the principal is correct, but I am baffled as to why the User.IsInRole line fails.

Create and read cookie to confirm logged in user in C# MVC3

I have a problem with cookies in MVC3. I want to create a cookie, that stores informations whether the user is logged in. I have never used cookies before and don't know what is the proper way to do it and I am new to MVC3.
Please, can somebody tell me if the approach I used to store cookie is proper or if there is some security risk (the password is encrypted)?
If the cookies are set correctly, how can I use them in other views to check if the user is logged in and set the session for him?
If the approach I use to log in user is wrong, just tell me.
public ActionResult Login(string name, string hash, string keepLogged)
{
if (string.IsNullOrWhiteSpace(hash))
{
Random random = new Random();
byte[] randomData = new byte[sizeof(long)];
random.NextBytes(randomData);
string newNonce = BitConverter.ToUInt64(randomData, 0).ToString("X16");
Session["Nonce"] = newNonce;
return View(model: newNonce);
}
User user = model.Users.Where(x => x.Name == name).FirstOrDefault();
string nonce = Session["Nonce"] as string;
if (user == null || string.IsNullOrWhiteSpace(nonce))
{
return RedirectToAction("Login", "Users");
}
string computedHash;
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashInput = Encoding.ASCII.GetBytes(user.Password + nonce);
byte[] hashData = sha256.ComputeHash(hashInput);
StringBuilder stringBuilder = new StringBuilder();
foreach (byte value in hashData)
{
stringBuilder.AppendFormat("{0:X2}", value);
}
computedHash = stringBuilder.ToString();
}
if (computedHash.ToLower() == hash.ToLower())
{
Session["IsAdmin"] = user.IsAdmin == 1;
Session["IDUser"] = user.IDUser;
ViewBag.IdUser = IDUser;
ViewBag.IsAdmin = IsAdmin;
ViewBag.UserName = model.Users.Where(x => x.IDUser == IDUser).First().Name;
if (keepLogged == "keepLogged")
{
//Set user's cookies - is this correct?
Response.Cookies.Add(new HttpCookie("UserCookie", user.IDUser.ToString()));
Response.Cookies.Add(new HttpCookie("PassCookie", user.Password.ToString()));
}
}
return RedirectToAction("Index", "Posts");
}
This code creates an encrypted cookie with the username
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
user.UserName,
DateTime.Now,
DateTime.Now.AddMinutes(10),
false,
null);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
this.Response.Cookies.Add(cookie);
To enable forms authentication add the following to the system.web section of the web.config:
<authentication mode="Forms">
<forms loginUrl="~/Logon" timeout="2880" />
</authentication>
No,You do not want to store the user's password in a custom cookie. Look into Forms Authetication. It does all the cookie work for you. You can set that forms authetication cookie to persist on the user's computer so that they "stay logged in".
here is my simlified version how you can work with cookies
for remember user name
/// <summary>
/// Account controller.
/// </summary>
public ActionResult LogOn()
{
LogOnModel logOnModel = new LogOnModel();
HttpCookie existingCookie = Request.Cookies["userName"];
if (existingCookie != null)
{
logOnModel.UserName = existingCookie.Value;
}
return View(logOnModel);
}
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (model.RememberMe)
{
// check if cookie exists and if yes update
HttpCookie existingCookie = Request.Cookies["userName"];
if (existingCookie != null)
{
// force to expire it
existingCookie.Value = model.UserName;
existingCookie.Expires = DateTime.Now.AddHours(-20);
}
// create a cookie
HttpCookie newCookie = new HttpCookie("userName", model.UserName);
newCookie.Expires = DateTime.Today.AddMonths(12);
Response.Cookies.Add(newCookie);
}
// If we got this far, something failed, redisplay form
return View(model);
}

How to get the cookie value in asp.net website

I am creating a cookie and storing the value of username after succesfull login. How can I access the cookie when the website is opened. If the cookie exist I want to fill the username text box from the cookie value. And how to decrypt the value to get the username. I am doing server side validation by getting the userdetails from the database. I am using vs 2010 with c#
FormsAuthenticationTicket tkt;
string cookiestr;
HttpCookie ck;
tkt = new FormsAuthenticationTicket(1, txtUserName.Value, DateTime.Now,
DateTime.Now.AddYears(1), chk_Rememberme.Checked, "User Email");
cookiestr = FormsAuthentication.Encrypt(tkt);
ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
if (chk_Rememberme.Checked)
{
ck.Expires = tkt.Expiration;
ck.Path = FormsAuthentication.FormsCookiePath;
Response.Cookies.Add(ck);
}
cookie is created with name as .YAFNET_Authentication and content is encrypted
Webconfig:
<forms name=".YAFNET_Authentication" loginUrl="Home.aspx"
protection="All" timeout="15000" cookieless="UseCookies"/>
You may use Request.Cookies collection to read the cookies.
if(Request.Cookies["key"]!=null)
{
var value=Request.Cookies["key"].Value;
}
FormsAuthentication.Decrypt takes the actual value of the cookie, not the name of it. You can get the cookie value like
HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName].Value;
and decrypt that.
add this function to your global.asax
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (authCookie == null)
{
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch
{
return;
}
if (authTicket == null)
{
return;
}
string[] roles = authTicket.UserData.Split(new char[] { '|' });
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id, roles);
Context.User = principal;
}
then you can use HttpContext.Current.User.Identity.Name to get username. hope it helps
HttpCookie cook = new HttpCookie("testcook");
cook = Request.Cookies["CookName"];
if (cook != null)
{
lbl_cookie_value.Text = cook.Value;
}
else
{
lbl_cookie_value.Text = "Empty value";
}
Reference Click here

Categories