MVC Custom Authorize Attribute to validate the Request - asp.net-mvc

I've a UI with Jquery which makes a call to MVC using Ajax request.
I would like to validate each request against the userProfile (custom class which holds account number, ID etc).
Could anyone please suggest whether it is possible to create custom Authorize Attribute to validate that both request and userprofile are same?
I would then like to do something like below:
[AuthorizeUser]
public ActionResult GetMyConsumption(string accountNumber)
{
.....
return View();
}

You could write a custom Authorize attribute:
public class AuthorizeUserAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
// The user is not authorized => no need to continue
return false;
}
// At this stage we know that the user is authorized => we can fetch
// the username
string username = httpContext.User.Identity.Name;
// Now let's fetch the account number from the request
string account = httpContext.Request["accountNumber"];
// All that's left is to verify if the current user is the owner
// of the account
return IsAccountOwner(username, account);
}
private bool IsAccountOwner(string username, string account)
{
// TODO: query the backend to perform the necessary verifications
throw new NotImplementedException();
}
}

Related

Passing string to Custom Authorize MVC

I have just created a custom Authorize method so that a User on the website I am building, is only able to see his/her view.
public class UserAuthorize : AuthorizeAttribute
{
public string Username { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
return false;
}
string username = httpContext.User.Identity.Name;
if(new RolesBL().IsUserInRole(username, 1))//1 is Admin
{
return true;
}
return Username.Equals(username);
}
}
I am having trouble passing through the data from the controller to this method
[UserAuthorize(Username = username)]
public ActionResult Details(string username)
{
User u = new UsersBL().GetUser(username);
return View(u);
}
How can I pass the username in the View's parameter to the Authorize method as well.
Thanks and Regards
This is not a case where using authorization makes sense. You should instead prevent the user from being able to pass in an argument to override the user that they are logged in as.
public ActionResult Details()
{
User u = new UsersBL().GetUser(this.User.Identity.Name);
return View(u);
}
Your query then acts as a filter to ensure only the logged in user's information is seen.
If you need a super user to be able to view/edit each user, then you would need to use a role to ensure that only users in that role can edit other users. But in that case, the standard AuthorizeAttribute will suffice.
public ActionResult Details()
{
User u = new UsersBL().GetUser(this.User.Identity.Name);
return View(u);
}
[Authorize(Roles = "SuperUser")]
public ActionResult Details(string username)
{
User u = new UsersBL().GetUser(username);
return View(u);
}
The arguments in an [Attribute] declaration are all defined at compile-time, and must therefore be constants. You can't "pass in" the run-time value of an action parameter.
Besides which, the attribute will be used prior to the action method being invoked (to determine whether the action can be invoked) - and so that parameter won't even be instantiated.
You might however be able to access the username value within the UserAuthorize attribute implementation, since the httpContext parameter gives you access to the request details, which presumably contains the user name as part of the query string.

Creating varying access levels using authentication

I have created an enum with security access levels, an example:
public enum AccessLevel
{
Total,
DeletionPrivileges,
MaintainUsers,
MaintainInventory,
QueriesOnly,
None
}
I can manage the site so certain features eg delete, are not presented to someone without deletion privileges. But I am also wanting to use some kind of authorisation within the code.
Within the default framework, there is the facility to prevent access to certain areas of a project using [Authorize], how can I create differing levels of authority to tag each method?
You could use claim based authentication feature of Identity to aim this purpose easily. First you need add proper claim per user in log in action method to do this change your log in action method like this:
[HttpPost]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var userManager=HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = userManager.Find(model.UserName, model.Password);
if (user != null)
{
var ident = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);
// imaging you have a custom class which return user access levels
var userAccessLevels=_accessLevelManager.GetAccessLevels(user.Id);
// now we are going to add our custom claims
ident.AddClaims(new[]
{
// add each access level as a separate claim
new Claim("AccessLevel",userAccessLevels[0].ToString()),
new Claim("AccessLevel",userAccessLevels[1].ToString()),
// and so on
});
HttpContext.GetOwinContext().Authentication.SignIn(new AuthenticationProperties { IsPersistent = false }, ident);
// authentication succeed do what you want
return Redirect(login.ReturnUrl ?? Url.Action("Index", "Home"));
}
}
ModelState.AddModelError("", "Invalid username or password");
return View(login);
}
Now we have successfully injected our claims to Identity. But you need a custom authorize attribute to check your claims like this:
public class ClaimsAccessAttribute : AuthorizeAttribute
{
public string ClaimType { get; set; }
public string Value { get; set; }
protected override bool AuthorizeCore(HttpContextBase context)
{
return context.User.Identity.IsAuthenticated
&& context.User.Identity is ClaimsIdentity
&& ((ClaimsIdentity)context.User.Identity).HasClaim(x =>
x.Type == ClaimType && x.Value == Value);
}
}
Now you could easily use your attribute in your action methods:
[ClaimsAccess(CliamType="AccessLevel",Value="DeletionPrivileges")]
public ActionResult MyAction()
{
// also you have access the authenticated user's claims
// simply by casting User.Identity to ClaimsIdentity
// ((ClaimsIdentity)User.Identity).Claims
}

User specific information accessible everywhere. How to secure it?

Using ASP.NET MVC 5 and Entity Framework. How can I secure my application so I cant access other users data?
To do CRUD stuff I have index, create, edit, delete methods in FooController so I can use:
/Foo/
to view my information I click one and get
/Foo/Details/5
When I type in 3 in the browser I get someone else's information.
/Foo/Details/3
How can I secure this from being accessed everywhere? I use Owin Identity and are logged into the application.
You could write a custom authorization filter by deriving from the AuthorizeAttribute class and inside you could check whether the currently authenticated user has access to the requested resource.
For example:
public class MyAuthorizeAttribute: AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
return false;
}
string id = httpContext.Request["id"];
string currentUser = httpContext.User.Identity.Name;
return HasAccessToResource(id, currentUser);
}
private bool HasAccessToResource(string id, string currentUser)
{
// You know what to do here => check in your backend whether the
// current user is authorized to access the specified resource id
throw new NotImplementedException();
}
}
and then decorate your controllers/actions with this custom attribute:
[MyAuthorize]
public ActionResult Delete(string id)
{
// if you get that far, the current user is owner of the requested resource
...
}

User Role Association per Domain Entity

I have the following structure in my DB:
DomainEntities:
+EntityID
+Name
+ParentID
+...
Users:
+UserID
+Username
+...
Roles:
+RoleID
+Name
UserRolesAssociation:
+RoleID
+UserID
+EntityID
So i want to use MVC's built in authorization attribute to filter action in my controllers that are made by different members.
I what to be able to say if user1 makes a delete action on entity1 or any entity under it i can see if he has the right role to do that and filter the action accordingly.
What would be the best practice to tackle that topic ?
Should i create my own permissions engine that will provide me the answers i need or can i use the existing capabilities ?
What would be the best practice to tackle that topic ?
A custom [Authorize] seems like a good place to implement this logic.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// the use ris not authenticated or not authorized - no need to continue
return false;
}
string username = httpContext.User.Identity.Name;
// read the entity id that this user is attempting to manipulate
string entityId = (string)httpContext.Request.RequestContext.RouteData.Values["id"] ?? httpContext.Request["id"];
return IsAllowed(username, entityId);
}
private bool IsAllowed(string username, string entityId)
{
// You know what to do here - hit the database and check whether
// the current user is the owner of the entity
throw new NotImplementedException();
}
}
and then:
[HttpDelete]
[MyAuthorize]
public ActionResult Delete(int id)
{
...
}

How use another database and session to authorization?

I'm building a Asp.net MVC3 aplication (with Razor) and I have a Data Base that have information about users and roles.
This is simplified scheme of my DB.
User(IDUser, Login, Password);
Role(IDRole, Name);
UserInRole(IDUser, IDRole); //Many to Many
Looks like this:
I read about use AuthorizeAttribute, to control pages for loged users, and with specific roles and I research about use My DB to control users and roles. So my questions is:
Is possible use my DB to manage users and roles and use [Authorize] in my actions? [If yes how i do that?]
Is possible use session in the place of cookie to manage login and use the Authorization native Asp.net MVC3? [if yes, how i do that? if no how use session otherwise?]
If possible please post code examples.
Not sure if I understood correctly, but you want to use the [Authorize] attribute to work with your custom users database?
If that's the case, there are somethings to check:
To simply allow/deny based whether the user is authorized or not, the stock [Authorize] attribute will work just fine. The custom logic goes in your Login action, where you will check the database with the given credentials and issue the cookie accordingly. Something like:
public ActionResult Login(string username, string password)
{
bool isValid = //check the database with the given username and password
if(isValid)
{
FormsAuthentication.SetAuthCookie(username, false);
return RedirectToAction("...");
}else
{
return View();
}
}
If you want to also control access based on roles, I would say there are 2 immediate ways:
Implement a custom Membership and Role providers, something I don't like as I find them pretty useless, and always end up redoing the logic in my respositories
Implement a custom AuthorizeAttribute, like
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Check based on these 2 properties:
// this.Roles
// this.Users
//against httpContext.User
//return true or false to indicate access or deny
}
}
Thanks Pedro. Based in your post I build this to use SESSION:
public class CustomAutorizeAttribute : AuthorizeAttribute
{
public List<string> Roles { get; set; }
public CustomAutorizeAttribute()
{
}
public CustomAutorizeAttribute(params string[] Roles)
{
this.Roles = new List<string>();
this.Roles.AddRange(Roles);
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
User user = (User)httpContext.Session["user"];
if (user != null)
{
if (Roles != null)
{
foreach (var role in user.Roles)
{
if (Roles.Exists(e => e == role)) return true;
}
return false; // User don't have any hole
}
else
{
return true; // The Attribute is used without roles.
}
}
else return false; // Not logged.
}
}
Post here to hope others.

Resources