Problem creating persistent authentication cookie: ASP.NET MVC - asp.net

OK, here's my code to create an authentication cookie:
// get user's role
List<UserType> roles = rc.rolesRepository.GetUserRoles(rc.userLoginRepository.GetUserID(userName));
List<string> rolesList = (from r in roles
select r.ToString()).ToList();
string[] rolesArr = rolesList.ToArray();
// create encryption cookie
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.AddDays(90),
createPersistentCookie,
String.Join(";",rolesArr) //user's roles
);
// add cookie to response stream
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
System.Web.HttpCookie authCookie = new System.Web.HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);
//FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
And here's my code in Global.asax to set the user roles into the user identity:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null || authCookie.Value == "")
{
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] roles = authTicket.UserData.Split(new char[] { ';' });
if (Context.User != null)
{
Context.User = new System.Security.Principal.GenericPrincipal(Context.User.Identity, roles);
}
}
catch
{
return;
}
}
However, if "createPersistentCookie" is TRUE in the top example, no persistent cookie is created. If I uncomment the last line like so:
//System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
then the persistent cookie is created on my hard drive. BUT then in the Global.asax code, the UserData field in "authTicket" is blank, so I can't set up the roles properly!
So I have to use SetAuthCookie to create a persistent cookie, but then for some reason the UserData field disappears from the persistent cookie.
What is the answer to this??

To create a persistent cookie you need to set the Expires property:
if (authTicket.IsPersistent)
{
authCookie.Expires = authTicket.Expiration;
}

Related

Cookies in ASP.NET-Call Back to another page

do you know how cookies works on ASP.NET? could you tell me?
and how to call the cookies to another page?
i have login form, and i use cookies. but i can't call that cookies to another page. i want to use some data from login form (it's like domain name, username and password) to do change password from changepassword.aspx form.
somebody please help me.
void Login_Click(object sender, EventArgs e)
{
string adPath = "LDAP://mydomain.com"; //Path to your LDAP directory server
LdapAuthentication adAuth = new LdapAuthentication(adPath);
try
{
if(true == adAuth.IsAuthenticated(txtDomain.Text, txtUsername.Text, txtPassword.Text))
{
//string groups = adAuth.GetGroups();
string groups = txtUsername.Text;
//Create the ticket, and add the groups.
bool isCookiePersistent = chkPersist.Checked;
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,
txtUsername.Text,DateTime.Now, DateTime.Now.AddMinutes(60), isCookiePersistent, groups);
//Encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
//Create a cookie, and then add the encrypted ticket to the cookie as data.
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
if(true == isCookiePersistent)
authCookie.Expires = authTicket.Expiration;
//Add the cookie to the outgoing cookies collection.
Response.Cookies.Add(authCookie);
//You can redirect now.
Response.Redirect(FormsAuthentication.GetRedirectUrl(txtUsername.Text, false));
}
else
{
errorLabel.Text = "Authentication did not succeed. Check user name and password.";
}
}
catch(Exception ex)
{
errorLabel.Text = "Error authenticating. " + ex.Message;
}
}
</script>
this is how use cookies in login form.
how can i use cookies in change password form?

If FormsAuthentication Ticket is set, why doesn't User.IsInRole(“Admin”) work?

In the debugger, if I dig into the User object, I can see the current member's UserData property, ((System.Web.Security.FormsIdentity(User.Identity)).Ticket.UserData, has "admin" in it.
User.Identity.IsAuthenticated works but User.IsInRole("admin") returns false.
If "admin" is in the UserData property, then why doesn't User.IsInRole("admin") return true?
In my login method I have the authentication ticket set up as follows:
FormsAuthenticationTicket _ticket = new FormsAuthenticationTicket(1, lUserName.Text, DateTime.Now, DateTime.Now.AddMonths(1), chk_remember.Checked, Role, FormsAuthentication.FormsCookiePath);
string encTicket = FormsAuthentication.Encrypt(_ticket);
HttpCookie _cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
if (chk_remember.Checked)
_cookie.Expires = DateTime.Now.AddMonths(1);
Response.Cookies.Add(_cookie);
you need to put this code in your Global.asax
protected void Application_AuthenticateRequest(Object sender,
EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id =
(FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
// Get the stored user-data, in this case, our roles
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}
for more information you can see this link form authentication

Authenticating user with second login

asp.net I am using a second login control to verify a users email. They will get an Email that directs them to a confirm login window. Not the login that is used in the web.config file. So. I assumed that when they entered the loggedin event the would be authenticated, but it seems they are not. All I want to do here is set the profile property 'confirmed' = Y. So I added code:
protected void Login1_LoggedIn(object sender, EventArgs e)
{
TextBox userName = (TextBox)Login1.FindControl("UserName");
string uname = userName.Text;
TextBox Password = (TextBox)Login1.FindControl("Password");
if (Membership.ValidateUser(userName.Text, Password.Text) == true)
{
BDrider bd = new BDrider();
string UserData = bd.getRidFromUsername(uname).ToString();
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, uname, DateTime.Now, DateTime.Now.AddMonths(3), false, UserData, FormsAuthentication.FormsCookiePath);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(authCookie);
if (User.Identity.IsAuthenticated)
{
Profile.confirmed = "Y";
}
Response.Redirect("~/Main/Main.aspx");
}
}
But on the IsAuthenticated line it returns false ???
Seems that you are creating the cookie and trying to "consume it" in the very same request. Unfortunately, this won't work. The forms authentication module will pick up the cookie and maintain the session starting from just the next request.
A possible workaround would be to redirect to an auxiliary page and perform your operation there and then redirect to Main.aspx. Your code would be then
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, uname, DateTime.Now, DateTime.Now.AddMonths(3), false, UserData, FormsAuthentication.FormsCookiePath);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(authCookie);
Response.Redirect( "Auxiliary.aspx" );
and in the Auxiliary.aspx:
if (User.Identity.IsAuthenticated)
{
Profile.confirmed = "Y";
}
Response.Redirect("~/Main/Main.aspx");
However, I don't quite get the if. If you are just issuing the forms cookie, the user surely is authenticated. Why it would be otherwise?

aspnet auth cookie twice in Request

I'm dealing with custom authentication cookie in AspNet web app.
Using asp:Login component, here is how user is authenticated:
void L_Authenticate(object sender, AuthenticateEventArgs e)
{
if (L.UserName == "john" && L.Password == "cookie")
{
FormsAuthenticationTicket ticket =
new FormsAuthenticationTicket(1, "john",
DateTime.Now,
DateTime.Now.AddSeconds(30),
false, "");
var cookieConnexion = new HttpCookie("myCookie");
cookieConnexion.Value = FormsAuthentication.Encrypt(ticket);
cookieConnexion.Expires = ticket.Expiration;
this.Response.Cookies.Set(cookieConnexion);
Z.Text = "<a href='/Prive/Home.aspx'>next</a>";
}
}
First of all, I don't set e.Authenticated = true or .ASPXAUTH cookie will be created. I don't want that. Second, I don't do Response.Redirect.
Now, in Global.asax, User is set in current HttpContext:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Request.IsAuthenticated)
{
}
else
{
var cookie = this.Request.Cookies["myCookie"];
if (cookie != null)
{
var ticket = FormsAuthentication.Decrypt(cookie.Value);
if (ticket != null)
{
HttpContext.Current.User =
new ClientRolePrincipal(new GenericIdentity(ticket.Name));
ticket = new FormsAuthenticationTicket(1, ticket.Name,
DateTime.Now,
DateTime.Now.AddSeconds(30),
false, ticket.UserData);
cookie.Value = FormsAuthentication.Encrypt(ticket);
cookie.Expires = ticket.Expiration;
this.Response.Cookies.Set(cookie);
}
}
}
}
First request to the app (using chrome dev tools, I track down cookies in request/responses headers):
0 cookie in request
0 cookie in response: ASP.NET_SessionId
User logs in:
1 cookie in request: ASP.NET_SessionId
1 cookie in response: myCookie
User browses to Home.aspx:
2 cookies in request: ASP.NET_SessionId, myCookie
1 cookie in response: myCookie (renewed)
OK.
Now, if on PreRender I display elements contained in this.Request.Cookies, I see twice myCookie. Why?
ASP.NET_SessionId, domain '' , path '/', value = nk1cy255quh32o45hxtg4x55
myCookie, domain '' , path '/', value = BF6246B7E5A5100AA59A7B7237B446...
myCookie, domain '' , path '/', value = BF6246B7E5A5100AA59A7B7237B446...

User is in role "admin" but [Authorize(Roles="admin")] won't authenticate

I found a great answer on SO describing how to set up custom user roles, and I've done the same in my project. So in my Login service I have:
public ActionResult Login() {
// password authentication stuff omitted here
var roles = GetRoles(user.Type); // returns a string e.g. "admin,user"
var authTicket = new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.AddMinutes(20), // expiry
false,
roles,
"/");
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(authTicket));
Response.Cookies.Add(cookie);
return new XmlResult(xmlDoc); // don't worry so much about this - returns XML as ActionResult
}
And in Global.asax.cs, I have (copied verbatim from the other answer):
protected void Application_AuthenticateRequest(Object sender, EventArgs e) {
var authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null) {
var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
var roles = authTicket.UserData.Split(new Char[] { ',' });
var userPrincipal = new GenericPrincipal(new GenericIdentity(authTicket.Name), roles);
Context.User = userPrincipal;
}
}
Then, in my ServicesController class, I have:
[Authorize(Roles = "admin")]
//[Authorize]
public ActionResult DoAdminStuff() {
...
}
I login as a user with the "admin" role, and that works. Then I call /services/doadminstuff - and I get access denied, even though when I put a breakpoint in Global.asax.cs, I can see that my roles do include "admin". If I comment out the first Authorize attribute (with roles) and just use a plain vanilla Authorize, then I can access the service.
I must be missing something critical here - but where to start looking?
I would recommend you use a custom authorize attribute instead of Application_AuthenticateRequest:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
string cookieName = FormsAuthentication.FormsCookieName;
if (!filterContext.HttpContext.User.Identity.IsAuthenticated ||
filterContext.HttpContext.Request.Cookies == null ||
filterContext.HttpContext.Request.Cookies[cookieName] == null
)
{
HandleUnauthorizedRequest(filterContext);
return;
}
var authCookie = filterContext.HttpContext.Request.Cookies[cookieName];
var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] roles = authTicket.UserData.Split(',');
var userIdentity = new GenericIdentity(authTicket.Name);
var userPrincipal = new GenericPrincipal(userIdentity, roles);
filterContext.HttpContext.User = userPrincipal;
base.OnAuthorization(filterContext);
}
}
and then:
[CustomAuthorize(Roles = "admin")]
public ActionResult DoAdminStuff()
{
...
}
Also a very important thing is to ensure that when you login an authentication cookie is emitted because you return an XML file. Use FireBug to inspect whether the authentication cookie is properly sent when you try to access the url /services/doadminstuff.
I would change principal assign at first:
Thread.CurrentPrincipal = userPrincipal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = userPrincipal;
}
as ASP.NET documentation stands.

Resources