HttpContext.Current.User.IsInRole not working - asp.net-mvc

in my controller AuthController/signin i have this code:
entities.UserAccount user = (new BLL.GestionUserAccount()).authentifier(email, password);
//storing the userId in a cookie
string roles = (new BLL.GestionUserAccount()).GetUserRoles(user.IdUser);
// Initialize FormsAuthentication, for what it's worth
FormsAuthentication.Initialize();
//
FormsAuthentication.SetAuthCookie(user.IdUser.ToString(), false);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
user.IdUser.ToString(), // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMinutes(30), // Date/time to expire
true, // "true" for a persistent user cookie
roles, // User-data, in this case the roles
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
// Get the stored user-data, in this case, our roles
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
// Add the cookie to the list for outgoing response
Response.Cookies.Add(cookie);
return RedirectToAction("index", "Home");
in the master page i have a menu ,in that menu there is an item that is meant to be seen only by admin role.
<% if (HttpContext.Current.User.IsInRole("admin")){ %>
<%=Html.ActionLink("Places", "Places", "Places")%>
<%} %>
even with HttpContext.Current.User conatining the right roles,i can't see the item:
globalx 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);
}
}
}
}

Instead of using User.IsInRole(), try the static method Roles.IsUserInRole().

I know it sounds silly but from your image I can only see your userData from your ticket.
The only thing I can think if is if the userData is not going into the principal. (Possibly a problem with the last three lines of glabal.asax.cs)
Something is wrong here:
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);

You will need a custom Authorize attribute which will parse the user data portion of the authentication ticket and manually create the IPrincipal. Take a look at this post which illustrates the way I would recommend you to do this in ASP.NET MVC. Never use HttpContext.Current in an ASP.NET MVC application. Not even in your views. Use <% if (User.IsInRole("admin")) { %> instead.

One statement is missing.
After this line:
FormsAuthenticationTicket ticket = id.Ticket;
You need to put this line:
ticket = FormsAuthentication.Decrypt(ticket.Name);

In global.asax assign principal on 2 objects like that:
private static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
I found it here ASP.NET documentation

Related

Logging out of Webforms Authentication dos not remove the authentication on the server

I use the out of the box webforms authentication.
After a request to "Logout" and using:
FormsAuthentication.SignOut();
The user is logged out by removing the cookie ".aspxauth" from the client browser.
This works as expected.
Our site got security audited and the auditor claimed that the authentication token does not get deleted from the server when the user logs out.
I can reproduce this behaviour using Fiddler.
I log in to the site and copy the cookie ".aspxauth"
I log out: the cookie is deleted on the client and I dont have access to secured pages anymore
I send a request to the site using fiddler composer using the prevously copied cookie "aspxauth". I can access secured pages with that cookie.
The expected result would be that if I log out I can not access secured pages by providing the old aspxauth cookie.
Is there a way to invalidate the old aspxauth cookie on the server?
I solved this by storing a salt value in the Auth-cookie that gets also saved in the Database for the user when he loggs in.
On each request there is a check if the salt in the auth cookie is the same as the one from the database. If not the user gets logged out.
If the User loggs out the salt gets deleted from the Database and the old auth - cookie cant be used anymore.
Store Salt when logging in
// Generate a new 6 -character password with 2 non-alphanumeric character.
string formsAuthSalt = Membership.GeneratePassword(6, 2);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
orderAuthToken.EMail,
DateTime.Now,
DateTime.Now.AddMinutes(20),
ApplicationConfiguration.CreatePersistentCookie,
formsAuthSalt,
FormsAuthentication.FormsCookiePath);
// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
UserInfo user = UserService.GetUser(orderAuthToken.EMail);
user.FormsAuthenticationCookieSalt = formsAuthSalt;
UserService.UpdateUser(user);
Check the salt in a filter you decoryte alle actions with
public class CheckFormsAuthenticationCookieSalt : ActionFilterAttribute
{
private readonly IUserService UserService = ObjectFactory.GetInstance<IUserService>();
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if ( filterContext.HttpContext.Request.IsAuthenticated)
{
// Encrypt the ticket.
if (HttpContext.Current.Request.Cookies.AllKeys.Contains(FormsAuthentication.FormsCookieName))
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
if (ticket != null)
{
string salt = ticket.UserData;
int userID = UserService.GetUniqueID(filterContext.HttpContext.User.Identity.Name, true, false, "MyAppName");
UserInfo user = UserService.GetUser(userID);
//for deployment: dont logg out existing users with no cookie
if (user.FormsAuthenticationCookieSalt != salt && user.FormsAuthenticationCookieSalt != "seed")
{
FormsAuthentication.SignOut();
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "action", "Index" }, { "controller", "Home" } );
}
}
}
}
}
base.OnActionExecuting(filterContext);
}
}

ASP.NET External Authentication Services Integration

My ASP.NET webapp will be protected by third party agent(SM). SM will intercept every call to the webapp, authenticate the user as valid system user, add some header info ex username and redirect it to my webapp. I then need to validate that the user is an active user of my website.
Currently I am authenticating the user by implementing the Application_AuthenticateRequest method in the Global.asax.cs file. I have a custom membership provider whose ValidateUser method, checks if the user exists in the users table of my database.
Just wanted to get comments if this was a good approach or not.
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
//if user is not already authenticated
if (HttpContext.Current.User == null)
{
var smcred = ParseAuthorizationHeader(Request);
//validate that this user is a active user in the database via Custom Membership
if (Membership.ValidateUser(smcred.SMUser, null))
{
//set cookie so the user is not re-validated on every call.
FormsAuthentication.SetAuthCookie(smcred.SMUser, false);
var identity = new GenericIdentity(smcred.SMUser);
string[] roles = null;//todo-implement role provider Roles.Provider.GetRolesForUser(smcred.SMUser);
var principal = new GenericPrincipal(identity, roles);
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
}
}
protected virtual SMCredentials ParseAuthorizationHeader(HttpRequest request)
{
string authHeader = null;
var smcredential = new SMCredentials();
//here is where I will parse the request header for relevant tokens ex username
//return smcredential;
//mockup below for username henry
return new SMCredentials() { SMUser = "henry", FirstName = "", LastName = "", EmailAddr = "" };
}
I would go with the Attribute approach to keep it more MVC like. It would also allow you more flexibility, you could potentially have different Membership Providers for different controllers/actions.

MVC 3 Authentication / Authorization: Roles missing

We use MVC 3. The default user management is not usable for us as our account info is stored in our own data-store and access goes via our own repository classes.
I'm trying to assign a principal add roles to the HttpContext.User and give out an authorization cookie.
Based on a code snipped I found I tried something like this:
if (UserIsOk(name, password))
{
HttpContext.User =
new GenericPrincipal(
new GenericIdentity(name, "Forms"),
new string[] { "Admin" }
);
FormsAuthentication.SetAuthCookie(name, false);
return Redirect(returnUrl);
}
When the next request is done, the user is authenticated, but he is not in the "Admin" role.
What am I missing?
I think you should implement FormsAuthenticationTicket.
More info here : http://msdn.microsoft.com/en-us/library/aa289844(v=vs.71).aspx
In Mvc it is quite similar.
I have a class called UserSession that is injected into LoginController and that I use in LogOn action :
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Index(LoginInput loginInput, string returnUrl)
{
if (ModelState.IsValid)
{
return (ActionResult)_userSession.LogIn(userToLog, loginInput.RememberMe, CheckForLocalUrl(returnUrl), "~/Home");
}
}
Here's my UserSession LogIn implementation (notice I put the "Admin" role hard coded for the example, but you could pass it as argument) :
public object LogIn(User user, bool isPersistent, string returnUrl, string redirectDefault)
{
var authTicket = new FormsAuthenticationTicket(1, user.Username, DateTime.Now, DateTime.Now.AddYears(1), isPersistent, "Admin", FormsAuthentication.FormsCookiePath);
string hash = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
if (authTicket.IsPersistent) authCookie.Expires = authTicket.Expiration;
HttpContext.Current.Response.Cookies.Add(authCookie);
if (!String.IsNullOrEmpty(returnUrl))
return new RedirectResult(HttpContext.Current.Server.UrlDecode(returnUrl));
return new RedirectResult(redirectDefault);
}
Then in the base controller I've overriden OnAuthorization method to get the cookie :
if (filterContext.HttpContext.Current.User != null)
{
if (filterContext.HttpContext.Current.User.Identity.IsAuthenticated)
{
if( filterContext.HttpContext.Current.User.Identity is FormsIdentity )
{
FormsIdentity id = filterContext.HttpContext.Current.User.Identity as FormsIdentity;
FormsAuthenticationTicket ticket = id.Ticket;
string roles = ticket.UserData;
filterContext.HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
I hope this helps. Let me know.
You sure, that roles are enabled, and there is such role?
If not, do following:
In Visual Studio:
Project -> ASP.NET Configuration
Then choose Security, enable roles. Create role "Admin".
Then try your approach

Asp.net mvc FormsAuthentication from a service

I'm looking at the nerddinner code and in their AuthenticationController, they have the following code:
if (String.IsNullOrEmpty(alias)) throw new ArgumentException("Value cannot be null or empty.", "alias");
FormsAuthenticationTicket authTicket = new
FormsAuthenticationTicket(1, //version
userdId.ToString(), // user name
DateTime.Now, //creation
DateTime.Now.AddMinutes(30), //Expiration
createPersistentCookie, //Persistent
alias); //since Classic logins don't have a "Friendly Name"
string encTicket = FormsAuthentication.Encrypt(authTicket);
this.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
My problem is that I want to move this code into a class that does not inherits from the Controller type. The problem with this is the last line of code where it sets the cookie; Response, which is specific to Controller.
How do I set encTicket to a cookie without having access to the controller? Is there a way to use FormsAuthentication class itself to d this?
You could have a method in your separate class which returns the cookie so that the only thing the controller has to do is add the cookie to the response. IMO cookie management (adding/deleting) is the responsibility of the controller:
var cookie = authService.CreateAuthCookie(userId, alias);
Response.AppendCookie(cookie);
This is how to add the encrypted ticket to the browser cookie without using a controller.
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
{
Expires = authTicket.Expiration,
Path = FormsAuthentication.FormsCookiePath
};
if (HttpContext.Current != null)
{
HttpContext.Current.Response.Cookies.Add(cookie);
}

Can't log in a user in MVC!

I have been scratching my head on this for a while now but still can't get it.
I'm trying to simply log in a user in an MVC2 application.
I have tried everything that I know to try but still can't figure out what I'm doing wrong.
Here are a few things that I have tried:
FormsAuthentication.SetAuthCookie( emailAddress, rememberMe );
var cookie = FormsAuthentication.GetAuthCookie( emailAddress, rememberMe );
HttpContext.Response.Cookies.Add( cookie );
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket( emailAddress, rememberMe, 15 );
FormsIdentity identity = new FormsIdentity( ticket );
GenericPrincipal principal = new GenericPrincipal(identity, new string[0]);
HttpContext.User = principal;
I'm not sure if any of this is the right thing to do (as it's not working).
After setting HttpContext.User = principal then Request.IsAuthenticated == true.
However, in Global.asax I have this:
HttpCookie authenCookie = Context.Request.Cookies.Get(
FormsAuthentication.FormsCookieName );
The only cookie that ever is available is the aspnet session cookie.
Any ideas at all would be much appreciated!
You're doing way too much work. It takes one function call to log someone in. Here's the boilerplate code from a new MVC 2 app:
private bool ValidateLogOn(string userName, string password)
{
if (String.IsNullOrEmpty(userName))
{
ModelState.AddModelError("username", "You must specify a username.");
}
if (String.IsNullOrEmpty(password))
{
ModelState.AddModelError("password", "You must specify a password.");
}
if (!MembershipService.ValidateUser(userName, password)) // this is the login
{
ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
}
return ModelState.IsValid;
}
Note the commented line. That's all you need to do a login. I note that you're not calling ValidateUser in your code in the question. You need that.

Resources