I am working on a project that uses an ASP.NET MVC application which has a page on there that only certain users should be able to access. Using Windows Authentication, I want to take the User.Identity.Name and check that against the LogonID field in my Users table in the database. If there is a match, I then want to check if the IsAdmin field equals true and if so, grant access to the desired page.
I am fairly new to this so I was wondering how I would need to go about it?
UPDATE:
So i've tried to use the AuthorizeAttribute which has been suggested to me but I have come across a problem.
I am using a SQL Server Compact Database without a DBContext. So I was wondering how I would write my entity in order to access the database?
public class AuthorizeAuthorAttribute : AuthorizeAttribute
{
//Entity to access Database
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
return false;
}
string currentUser = httpContext.User.Identity.Name;
var userName = //Linq statement
string my = userName.ToString();
if (currentUser.Contains(my))
{
return true;
}
else
{
return false;
}
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
You could implement custom Authorize filter and decorate the required controller with this filter. Inside custom filter Authorize core method, check the windows identity against your database and return true/false accordingly.
https://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.authorizecore(v=vs.118).aspx
Related
I am new to ASP.NET MVC and learning how to custom Roles using FormAuthentication from this tutorial link
This code below is stored the Roles. It works fine when I perform this [Authorize(Roles="admin")] in the controller
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (userDbEntities entities = new userDbEntities())
{
User user = entities.Users.SingleOrDefault(u => u.username == username);
roles = user.Roles;
}
//let us extract the roles from our own custom cookie
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
Is there a way to get the actual Role Name based on the current User.Identity? like below pseudo-code.
[Authorize]
public ActionResult Index()
{
bool isAdmin = System.Web.HttpContext.Current.User.IsInRole("admin"); // This also works correctly.
Response.Write("role: " + isAdmin);
string roleName = // The Code of How to get the actual Role Name
Response.Write("roleName: " + roleName); //e.g Admin, User...
return View();
}
From Comment: Do you know any good article about OWIN cookie
authentication for custom table for username and roles?
It has few pieces, so I created a sample project in GitHub AspNetMvcActiveDirectoryOwin. The original souce is to authenticate with AD, but you just need to modify ActiveDirectoryService class where you query custom tables.
The following three are the main classes -
AccountController
ActiveDirectoryService
OwinAuthenticationService replaces FormsAuthentication.
i am doing this in order to authorize user.
[Authorize(Users = #"user1, user2, user3")]
public class MyController : Controller
{
// my stuff
}
i want to do authorization from the list of user which are in database table..
This is how I got it done:
Create a new class (which inherits from AuthorizeAttribute class).
public class CustomAuthorizeAttribute : AuthorizeAttribute
Override the AuthorizeCore method (in CustomAuthorizeAttribute class) and include your custom logic in it.
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool isUserAuthorized = false;
// custom logic goes here
// You can get the details of the user making the call using httpContext
// (httpContext.User.Identity.Name)
// Then get the information you have stored on your db, and compare it
// with these details.
// Set isUserAuthorized to true if the values match
return isUserAuthorized;
}
Decorate your controller action method with the attribute that you just created.
[CustomAuthorize]
public ActionResult DoSomething(string something, string someOtherThing)
This link form Gotalove is helpful.
try the following:
"using the link shared by #VikasRana http://www.codeproject.com/Articles/578374/AplusBeginner-splusTutorialplusonplusCustomplusF
I got rid of my enum Role and my method
public CustomAuthorizeAttribute(params object[] roles)
{ ...}
I then changed Role in my model to be a string e.g. User.Role="Admin" instead of int. In my onAuthorization method I changed it to:
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Controller.TempData["ErrorDetails"] = "You must be logged in to access this page";
filterContext.Result = new RedirectResult("~/User/Login");
return;
}
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Controller.TempData["ErrorDetails"] = "You don't have access rights to this page";
filterContext.Result = new RedirectResult("~/User/Login");
return;
}
}
and in my global.asax added this.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true && Request.IsAuthenticated== true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (GManagerDBEntities db = new GManagerDBEntities())
{
User user = db.Users.SingleOrDefault(u => u.Username == username);
roles = user.Role;
}
//let us extract the roles from our own custom cookie
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
//something went wrong
}
}
}
}
"
Source: Custom user authorization based with roles in asp.net mvc
PS.: In this link, in the same post, there is a second way to fix your problem.
In the bottom of the post.
If this can't to help you, you should try it to.
I am working on an asp.net mvc 4 web application , and i wrote the following custom authorization class:-
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CheckUserPermissionsAttribute : AuthorizeAttribute
{
public string Model { get; set; }
public string Action { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (!httpContext.Request.IsAuthenticated)
return false;
//code goes here
if (!repository.can(ADusername, Model, value)) // implement this method based on your tables and logic
{
return false;
//base.HandleUnauthorizedRequest(filterContext);
}
return true;
// base.OnAuthorization(filterContext);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var viewResult = new JsonResult();
viewResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
viewResult.Data = (new { IsSuccess = "Unauthorized", description = "Sorry, you do not have the required permission to perform this action." });
filterContext.Result = viewResult;
}
else
{
var viewResult = new ViewResult();
viewResult.ViewName = "~/Views/Errors/_Unauthorized.cshtml";
filterContext.Result = viewResult;
}
base.HandleUnauthorizedRequest(filterContext);
}
}
}
but the only problem i am facing now is that if the authorization fail then the user will be prompted to enter username and password, although i have override the HandleUnauthorizedRequest to return a view or JSON based on if the request is AJAX or not. so can you advice why the user is being prompted to enter his username and password when the authorization fail, instead of receiving the _unauthorized view or the JSON containing an error message
but the only problem i am facing now is that if the authorization fail
then the user will be prompted to enter username and password,
although i have override the HandleUnauthorizedRequest to return a
view or JSON based on if the request is AJAX or not.
That's because you are absolutely always hitting the following line in your HandleUnauthorizedRequest method:
base.HandleUnauthorizedRequest(filterContext);
You know what this line do? It calls the base method. You know what the base method do? It returns 401 status code. You know what happens when 401 status response code is returned in an ASP.NET application in which you are using Forms Authentication? You get the login page.
So yeah, if you are using AJAX or something and intend to be returning some JSON or something make sure that the base stuff is never called. By the way in your else condition you seem to be attempting to render some ~/Views/Errors/_Unauthorized.cshtml view which obviously is useless once again because you are also calling the base method which will simply redirect to the login page.
I think that at this stage of my answer you already know what to do: get rid of this last line of your HandleUnauthorizedRequest method in which you are throwing all your efforts into the trash by calling the base method.
And if you want to do things properly and return 401 status code and not get the login page but instead return some custom JSON you could use the SuppressFormsAuthenticationRedirect property on the Response object. And if you are using some legacy version of the .NET framework which doesn't have this property you might find the following blog post useful in which Phil Haack explains how to handle this case.
I am having a hard time implementing "Remember Me" functionality in an MVC application with a custom principal. I have boiled it down to ASP.NET not retrieving the authentication cookie for me. I have included a snapshot below from Google Chrome.
Shows the results of Request.Cookies that is set within the controller action and placed in ViewData for the view to read. Notice that it is missing the .ASPXAUTH cookie
Shows the results from the Chrome developer tools. You can see that .ASPXAUTH is included here.
What may be the issue here? Why does ASP.NET not read this value from the cookie collection?
My application uses a custom IPrincipal. BusinessPrincipalBase is a CSLA object that ust implements IPrincipal. Here is the code for that:
[Serializable()]
public class MoralePrincipal : BusinessPrincipalBase
{
private User _user;
public User User
{
get
{
return _user;
}
}
private MoralePrincipal(IIdentity identity) : base(identity)
{
if (identity is User)
{
_user = (User)identity;
}
}
public override bool Equals(object obj)
{
MoralePrincipal principal = obj as MoralePrincipal;
if (principal != null)
{
if (principal.Identity is User && this.Identity is User)
{
return ((User)principal.Identity).Equals(((User)this.Identity));
}
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public static bool Login(string username, string password)
{
User identity = User.Fetch(username, password);
if (identity == null || !identity.IsAuthenticated)
{
identity = (User)User.UnauthenicatedIdentity;
}
MoralePrincipal principal = new MoralePrincipal(identity);
Csla.ApplicationContext.User = principal;
Context.Current.User = identity;
return identity != null && identity.IsAuthenticated;
}
public static void Logout()
{
IIdentity identity = User.UnauthenicatedIdentity;
MoralePrincipal principal = new MoralePrincipal(identity);
ApplicationContext.User = principal;
Context.Current.User = identity as User;
}
public override bool IsInRole(string role)
{
if (Context.Current.User == null || Context.Current.Project == null)
{
return false;
}
string userRole = Context.Current.User.GetRole(Context.Current.Project.Id);
return string.Compare(role, userRole, true) == 0;
}
The application also uses a custom membership provider. Here is the code for that.
public class MoraleMembershipProvider : MembershipProvider
{
public override bool ValidateUser(string username, string password)
{
bool result = MoralePrincipal.Login(username, password);
HttpContext.Current.Session["CslaPrincipal"] = ApplicationContext.User;
return result;
}
#region Non-Implemented Properties/Methods
public override string ApplicationName
{
get
{
return "Morale";
}
set
{
throw new NotImplementedException();
}
}
// Everything else just throws a NotImplementedException
#endregion
}
I do not think that any of this is related because the bottom line is that the Request.Cookies does not return the authentication cookie. Is it related to the size of the cookie? I heard there are issues to the size of the cookie.
UPDATE: It seems that the issue revolves around subdomains. This site was being hosted with a subdomain and the cookie domain was left blank. Does anyone have any pointers on how I can get the auth cookie to work with all domains (e.g. http://example.com, http://www.example.com, and http://sub.example.com)?
If you are trying to store the actual User object in the cookie itself, it is probably too big to store as a cookie. I am not too familiar with the MVC authentication stuff, but in web forms I generally do the following:
FormsAuthentication.RedirectFromLoginPage(user_unique_id_here, false);
The second parameter is for the persistency you are looking for.
From there I create a custom context (UserContext) that I populate via HttpModule that gives me access to all the user and role information.
Since I do not develop in MVC (yet) or CSLA, I'm not sure how much more help I can be. If I were you, I would also ditch the custom membership provider. You might as well just call MoralePrincipal.Login directly in your Authentication controller.
The rememberMe stuff should be set by the FormsAuthenticationService (in MVC2) or the FormsAuthentication static class in MVC1, if you're using the 'regular' AccountController's code. If you changed that code, did you remember to add in the (optional) boolean param indicating whether to use a persistent cookie or not?
It sounds to me like you're getting a session cookie, but not a persistent cookie.
In a custom role provider (inheriting from RoleProvider) in .NET 2.0, the IsUserInRole method has been hard-coded to always return true:
public override bool IsUserInRole(string username, string roleName) { return true; }
In an ASP.NET application configured to use this role provider, the following code returns true (as expected):
Roles.IsUserInRole("any username", "any rolename"); // results in true
However, the following code returns false:
Roles.IsUserInRole("any rolename"); // results in false
Note that User.IsInRole("any rolename") is also returning false.
Is this the expected behavior?
Is it incorrect to assume that the overload that only takes a role name would still be invoking the overridden IsUserInRole?
Update: Note that there doesn't seem to be an override available for the version that takes a single string, which has led to my assumption in #2.
I looked at Roles.IsUserInRole(string rolename) in .net reflector, and it resolves to the following:
public static bool IsUserInRole(string roleName)
{
return IsUserInRole(GetCurrentUserName(), roleName);
}
I would take a look at your current user. Here's why:
private static string GetCurrentUserName()
{
IPrincipal currentUser = GetCurrentUser();
if ((currentUser != null) && (currentUser.Identity != null))
{
return currentUser.Identity.Name;
}
return string.Empty;
}
I would be willing to bet this is returning an empty string because you either don't have a Current User, or its name is an empty string or null.
In the IsUserInRole(string username, string roleName) method, there is the following block of code right near the beginning:
if (username.Length < 1)
{
return false;
}
If your GetCurrentUserName() doesn't return anything meaningful, then it will return false before it calls your overridden method.
Moral to take away from this: Reflector is a great tool :)
Also beware if you have selected cacheRolesInCookie="true" in the RoleManager config. If you have added a new role to the database, it might be looking at the cached version in the cookie.
I had this problem and the solution was to delete the cookie and re-login.
This may help someone - be aware:
If you are using the login control to authenticate - the username entered into the control becomes the HttpContext.Current.User.Identity.Name which is used in the Roles.IsUserInRole(string rolename) and more specifically - the membership's GetUser() method. So if this is the case make sure you override the Authenticate event, validate the user in this method and set the username to a value that your custom membership provider can use.
protected void crtlLoginUserLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
bool blnAuthenticate = false;
string strUserName = crtlLoginUserLogin.UserName;
if (IsValidEmail(strUserName))
{
//if more than one user has email address - must authenticate by username.
MembershipUserCollection users = Membership.FindUsersByEmail(strUserName);
if (users.Count > 1)
{
crtlLoginUserLogin.FailureText = "We are unable to determine which account is registered to that email address. Please enter your Username to login.";
}
else
{
strUserName = Membership.GetUserNameByEmail(strUserName);
blnAuthenticate = Membership.ValidateUser(strUserName, crtlLoginUserLogin.Password);
//setting the userLogin to the correct user name (only on successful authentication)
if (blnAuthenticate)
{
crtlLoginUserLogin.UserName = strUserName;
}
}
}
else
{
blnAuthenticate = Membership.ValidateUser(strUserName, crtlLoginUserLogin.Password);
}
e.Authenticated = blnAuthenticate;
}