HTTPContext User Set In BeginRequest Not Available In Controller - c#

I am rolling with a somewhat homebrew method of authenticating users. After authenticating the user, the authentication ticket is set like so in C#.
FormsAuthenticationTicket authenticationTicket = new FormsAuthenticationTicket(1, viewModel.Email, DateTime.Now, DateTime.Now.AddHours(48), true, String.Join("|", roles));
string encryptedTicket = FormsAuthentication.Encrypt(authenticationTicket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(authCookie);
With a small note that roles is a string list built out of the available roles to that user (The roles are not within the same user table - e.g. there is a set of conditions that define a user "role").
Next within the Application_BeginRequest method in Global.asax I have the following :
// Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (null == authCookie)
{
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
return;
}
if (null == authTicket)
{
return;
}
string[] roles = authTicket.UserData.Split(new char[] { '|' });
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id, roles);
HttpContext.Current.User = principal;
Basically setting the current context with the user from the authticket. However, I first ran into an issue as I was doing a custom Authorize attribute for an MVC class, and I noticed that the User of the HTTPContext was NOT set.
I then noticed that within each action, the User was not set either. I can clearly see however by stepping through my code, that the user IS being found within the authentication ticket and being decrypted OK and stored in the context variable. But by the time I get to an action within any controller, the User has vanished from the context.
EDIT :
It should also be noted that other values set on the HTTPContext do carry over to the controller. e.g. this line
HttpContext.Current.AllowAsyncDuringSyncStages = false; // Or true
Will carry whatever I set it to into the controller action. It seems to only be the User that gets blanked.

Application_BeginRequest is not a valid place to set HttpContext.Current.User, As it will be overwritten during Authorization.
You need to implement the above code in Application_AuthorizeRequest.For example refer to below code. Then it will be available in controller.
public MvcApplication()
{
this.AuthorizeRequest += MvcApplication_AuthorizeRequest;
}
void MvcApplication_AuthorizeRequest(object sender, EventArgs e)
{
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket("test", true, 30);
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id, new string[] { });
HttpContext.Current.User = principal;
}

Related

SetPrincipal (#User.Identity.Name) from a cookie in ASP.Net MVC

I like to know how I can set the #User.Identity.Name via a cookie when a user clicks on a remember me checkbox.
Cookie code
if (_model.RememberMe)
{
HttpCookie cookie = new HttpCookie("login");
cookie.Values.Add("username", _model.Username);
cookie.Expires = DateTime.Now.AddDays(30);
Response.Cookies.Add(cookie);
}
First login code
if (Membership.ValidateUser(Username,Password))
{
RememberMe();
FormsAuthentication.RedirectFromLoginPage(Username, false);
}
On the first login the Identity.name is set but when I close the browser and go back on to the site. it logs in correctly without the user putting in their credentials but the Identity.name is empty.
if (Request.Cookies["login"] != null)
{
// We know the automatic log in has worked as it comes into here...
}
What do I need to do once the user by passes the login page so I can setup the iPrincipal object?
Thanks
Try below code please
Note : please check it on page view not in the same method on creation of cokies
private void CreateCokies(string userName)
{
var authTicket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(30), true, userName);
string cookieContents = FormsAuthentication.Encrypt(authTicket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieContents)
{
Expires = authTicket.Expiration,
Path = FormsAuthentication.FormsCookiePath
};
Response.Cookies.Add(cookie);
}

MVC Forms Authentication and Session, Authorize Issues

I have a MVC project that I'm using Forms Authentication, and I had to implement Roles for certain pages, so I got this in global.asax:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null || authCookie.Value == "")
{
return;
}
FormsAuthenticationTicket authTicket;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch
{
return;
}
string[] roles = authTicket.UserData.Split(';');
if (Context.User != null)
{
Context.User = new GenericPrincipal(Context.User.Identity, roles);
}
}
And I save the user roles when I log in my model:
//After checking login/password
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie == null)
{
cookie = new HttpCookie(FormsAuthentication.FormsCookieName);
HttpContext.Current.Response.Cookies.Add(cookie);
}
string userRoles = null;
if (users[i].PerfilID == UserRanks.Admin)
{
userRoles = "Admin;Users";
}
else
{
userRoles = "Users";
}
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0,
users[i].Name,
DateTime.Now,
DateTime.Now.AddDays(1),
false,
userRoles,
FormsAuthentication.FormsCookiePath
);
cookie.Value = FormsAuthentication.Encrypt(ticket);
HttpContext.Current.Response.Cookies.Set(cookie);
HttpContext.Current.Session["UserID"] = users[i].UserID;
HttpContext.Current.Session["LastLogin"] = users[i].LastLogin;
HttpContext.Current.User = new GenericPrincipal(HttpContext.Current.User.Identity, userRoles.Split(';'));
To retrieve the values of the session variables, I have a static property:
public static int UserID
{
get
{
object sessionData = HttpContext.Current.Session["UserID"];
if (sessionData == null)
{
//I had something here...
return 0;
}
return Convert.ToInt32(sessionData);
}
private set { }
}
Before I implemented roles authorization, I used to save the UserID in the cookie userData, and if the UserID in the session, when requested, was null, I'd retrieve it from the cookie instead (and set it to the session again).
Now the userData is being used to the roles management and I'm having issues with the session dropping faster than the cookie expiration, and I have users logged in which I can't retrieve their UserIDs and thus fails for all operations.
So I have to put a checker in each controller function such as:
if (MyUser.Session.UserID == 0)
{
//redirect to Login
}
...which defeats the whole purpose of using [Authorize] I guess.
Is there a better way to handle login expiration and session variables like this?
I thought about using JSON or some other format and save a bunch of userData in the cookie, but I'd like something simpler, if possible.
Also, I'm doing this in the login:
HttpContext.Current.User = new GenericPrincipal(HttpContext.Current.User.Identity, userRoles.Split(';'));
Which seems to be about the same the AuthenticateRequest does (I got that part from elsewhere, seemed to be the recommended way to handle member roles), but it doesn't work like it should. The user always gets redirected out on the [Authorize(Roles="Admin")] or even the [Authorize] only functions if I leave only that (and remove the global.asax part). Why?

How to get custom data out of generic principal inside an aspx code behind?

I am building an application and integrating it with active directory.
So I authenticate my app user to active directory users, after that I store some of user's data like : user group and user profile to Generic principal and user identity to Generic identity.
My problem is I can't get user profile data from generic principal when I want to use it.
Can someone show me how to do that?
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (authCookie == null)
{
//There is no authentication cookie.
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
//Write the exception to the Event Log.
return;
}
if (authTicket == null)
{
//Cookie failed to decrypt.
return;
}
String data = authTicket.UserData.Substring(0, authTicket.UserData.Length -1);
string[] userProfileData = data.Split(new char[] { '|' });
//Create an Identity.
GenericIdentity id =
new GenericIdentity(authTicket.Name, "LdapAuthentication");
//This principal flows throughout the request.
GenericPrincipal principal = new GenericPrincipal(id, userProfileData);
Context.User = principal;
Note : Code above is in global asax file, and I want to use user profile data which I stored in generic principal in another file named default.aspx.
So first off you shouldn't be doing this:
GenericPrincipal principal = new GenericPrincipal(id, userProfileData);
//^^ this is wrong!!
The second argument to the constructor is for Roles. See the docs.
If you want to store data into the generic principal then what you should do is
Create a class out of GenericIdentity :
class MyCustomIdentity : GenericIdentity
{
public string[] UserData { get; set;}
public MyCustomIdentity(string a, string b) : base(a,b)
{
}
}
Create it like this:
MyCustomIdentity =
new MyCustomIdentity(authTicket.Name,"LdapAuthentication");
//fill the roles correctly.
GenericPrincipal principal = new GenericPrincipal(id, new string[] {});
Get it in the page like this:
The Page class has a User property.
So for example in Page load you could do this:
protected void Page_Load(object sender, EventArgs e) {
MyCustomIdentity id = (MyCustomIdentity)this.User.Identity
var iWantUserData = id.UserData;
}
You can also use the following code:
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
string userData = id.Ticket.UserData

What is the proper way to implement Form Authentication along side Facebook/Other authentication in ASP.NET MVC

I am building an application in ASP.NET MVC 3 in which I have implemented Forms authentication.
I would also like to give the user the option to Sign-up/log-in with their facebook account(and possibly other social accounts in the future.)
I am using the C# Facebook SDK
I have successfully implemented the facebook login workflow. Now my question is, how to handle mixing both Forms and Facebook Auth? I can't seem to find any sufficient examples of how to accomplish this.
In regards to my facebook implementation, I am requesting permission from the user for a non-expiring Auth Token which I will store in my database.
For this you will have to do something like this
Create a custom class (CurrentIdentity) which implements IIdentity. Override .ToString() for this class, and so that you have some sort of serialized state of object. I had use "|" seperator. This string will be stored in encrypted cookie.
Create a session cookie
public static HttpCookie AuthCookie(CurrentIdentity identity) {
//Create the Authticket, store it in Cookie and redirect user back
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,
identity.Name, DateTime.Now, DateTime.Now.AddHours(3), true, identity.ToString(), FormsAuthentication.FormsCookiePath);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authCookie.Expires = authTicket.Expiration;
return authCookie;
}
Add this cookie to response.
HttpResponse res = HttpContext.Current.Response;
res.Cookies.Add(Helper.AuthCookie(identity));
res.Redirect(FormsAuthentication.GetRedirectUrl(identity.Name, true));
res.End();
Now in Gloabl.asax, inside *Application_AuthenticateRequest* read this cookie and populate your CurrentIdentity object, something like this.
if (Request.IsAuthenticated == true) {
// Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (null == authCookie) {
// There is no authentication cookie.
return;
}
FormsAuthenticationTicket authTicket = null;
try {
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
} catch (Exception) {
// Log exception details (omitted for simplicity)
return;
}
if (null == authTicket) {
// Cookie failed to decrypt.
return;
}
// When the ticket was created, the UserData property was assigned a
// pipe delimited string of role names.
string[] userInfo = authTicket.UserData.Split('|');
// Create an Identity object
FormsIdentity id = new FormsIdentity(authTicket);
//Populate CurrentIdentity, from Serialized string
CurrentIdentity currentIdentity = new CurrentIdentity(userInfo[0], userInfo[1], userInfo[2]);
System.Security.Principal.GenericPrincipal principal = new System.Security.Principal.GenericPrincipal(currentIdentity, userInfo);
Context.User = principal;
}
This should solve your problem. I have implemented similar thing on my company's website.
merge facebook authentication with your forms authentication.
When user login using forms auth you create FormsAuthenticationTicket, when login from facebook also create FormsAuthenticationTicket

FormsAuthentication with dynamic roles

i have a application with a roles table and a permission (user permissions per form) table different roles has different access levels and each user has specific access permissions to each form .
can i implement it using FormsAuthentication ?
thank you
You have to pass the list or roles to FormsAuthenticationTicket
Here is the complete code, I have added comments as well.
protected void lbtnSignIn_Click(object sender, EventArgs e)
{
.......Login credential checking code......
.......If the use verified, then add the roles to FormsAuthenticationTicket
.......I am assuming in the below code, you are getting list of roles from DB in DataTable
String roles = String.Empty;
if (dtblUsersRoles.Rows.Count > 0)
{
for (int count = 0; count < dtblUsersRoles.Rows.Count; count++)
{
//build list of roles in comma seperate
roles = roles + "," + dtblUsersRoles.Rows[count]["RoleName"].ToString();
}
}
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, txtUserID.Text,
DateTime.Now, DateTime.Now.AddMinutes(30), false, roles.Substring(1, roles.Length - 1), FormsAuthentication.FormsCookiePath);
string hashCookies = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashCookies);
Response.Cookies.Add(cookie);
}
then you can check the user, if he lies in certain role
if (HttpContext.Current.User.IsInRole("Super Admin"))
{
...................
}
It sounds like you could build a custom forms authentication provider in this case.
Here is an example
http://www.codeproject.com/KB/web-security/AspNetCustomAuth.aspx

Categories

Resources