I've recently started to investigate Breezejs.
I'm working on a system which will be used by multiple customers and I can't expose one customers data to another. How does Breezejs ensures that or what is the standard/recommended way of implementing this.
Say my entities are
Customer with properties Id, Name
Registered Emails with properties Id, Email, CustomerId
I keep the CustomerId in session when the user logs in, I don't allow user in my UI to send the customer id but how can I stop a malicious user from hand crafting a request and accessing other customers information?
Simplest way is to return your IQueryables on the server with a customer id restriction. Something like this:
[BreezeController]
public class NorthwindIBModelController : ApiController {
...
// initialize this from your session data
private var currentCustomerId;
[HttpGet]
public IQueryable<Customer> Customers() {
return ContextProvider.Context.Customers.Where(cust => cust.Id == currentCustomerId);
}
[HttpGet]
public IQueryable<Email> RegisteredEmails() {
return ContextProvider.Context.Emails.Where(email => email.CustomerId == currentCustomerId);
}
}
Does this make sense?
That's certainly the simplest, however, it has NO way to protect against someone deleteing/updating the very same restricted entries as this query isn't taken into account during a save. Only the EntityType gets sent to SaveChanges.
Related
Basically I've spent the last few days trying to figure out how to add simple Admin and Member roles onto a website I'm developing for a friend. (I am using ASP.NET Framework 5.2.7.0). I know that Microsoft has a nice role based access feature built in which allows you to put something like [Authorize Role=("Admin") at the top of the controller; however I have not been able to get it to work at all and most of the resources I've found are for ASP.NET Core.
I've tried modifying my web.config file to enable the role based access (and hopefully migrate the roles and such to my database). But since I've been unable to figure any of this out, I've tried going a more hacky route. (**I am not an advanced programmer, I've been doing this for about a year now and am in no way a pro). This is what I've basically come up with in my attempt to verify if a user is an admin (which also didn't work).
[Authorize]
public class AdminController : Controller
{
private LDSXpressContext db = new LDSXpressContext();
public ActionResult AdminPortal()
{
IsAdmin();
return View();
}
private ActionResult IsAdmin()
{
string name = User.Identity.Name;
//The User.Identity.Name stores the user email when logged in
var currentUserObject = db.accounts.Where(x => x.clientEmail == name);
Account currentUser = new Account();
foreach (var user in currentUserObject)
{
//I loop through the results, even though only one user should
//be stored in the var CurrentUserObject because it's the only
//way I know how to assign it to an object and get its values.
currentUser = user;
}
if (currentUser.role == 2) //the number 2 indicates admin in my db
{
return null;
}
else
{
//Even when this is hit, it just goes back and returns the
//AdminPortal view
return RedirectToAction("Index", "Home");
}
}
}
Now I'm nearly positive that is is NOT a very secure way to check if a signed in user is an admin, but I was hoping that it would at least work. My idea was when someone attempted to access the AdminPortal, the IsAdmin method would run and check if the user is an admin in the database. If they are, then it returns null and the AdminPortal view is displayed, if they are not an Admin, then they are redirected to the Index view on the home page. However, the AdminPortal page is always displayed to any user and this doesn't seem to work either. I've even stepped into the code and watched it run over the return RedirectToAction("Index", "Home"); action, but then it jumps back to the AdminPortal method and just returns the AdminPortal view. So my question is:
1) If anyone happens to have experience with Role Based access in ASP.NET Framework, I would love some tips on how to get it set up
or,
2) If all else fails and I need to use my hacky method, why does it continue to return the AdminView even when the user is not an admin.
**Note: I know I could create a function that returns true or false if the user is an Admin or not, and then have an if/else statement in the AdminPortal controller that will return on view for true and another for false, however I don't want to have to implement that onto every ActionMethod, it'd be nice to keep it down to one line, or just the [Authorize Role="Admin] above the controller if possible.
Thank you guys so much for any help provided, I've been trying to research and fix this for days now and decided to reach out and ask the community!
At a minimum, you'll want to make some adjustments to what you're doing:
[Authorize]
public class AdminController : Controller
{
public ActionResult AdminPortal()
{
if(IsAdmin())
{
return View();
}
return RedirectToAction("Index", "Home");
}
private bool IsAdmin()
{
bool isAdmin = false;
using(LDSXpressContext db = new LDSXpressContext())
{
string name = User.Identity.Name;
//The User.Identity.Name stores the user email when logged in
// #see https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.singleordefault
var currentUser = db.accounts.SingleOrDefault(x => x.clientEmail.Equals(name, StringComparison.OrdinalIgnoreCase));
// If the email doesn't match a user, currentUser will be null
if (currentUser != null)
{
//the number 2 indicates admin in my db
isAdmin = currentUser.role == 2;
}
}
return isAdmin;
}
}
First off, DbContext instances are meant to used, at most, per the lifetime of an HTTP request. Moving it from the class / controller level and placing it within a using block makes sure that it's properly disposed.
Next, your IsAdmin function really just needs to return a true/false value based on your lookup, and then the AdminPortal action can decide what to do with that result.
Since email seems to be a unique field in your table, use the SingleOrDefault or FirstOrDefault LINQ extension to fetch a single matching record. Which one you use is up to you, but if it's truly a unique value, SingleOrDefault makes more sense (it will throw an exception if more than one row matches). Using the StringComparison flag with the String.Equals extension method makes your search case-insensitive. There are a few culture-specific versions of that, but ordinal matching is what I would normally use, here.
Implementing some version of the Identity framework is a bit too long for an answer here, but it's possible to implement a claims-based authentication scheme without too much work. That's something that probably needs a separate answer, though.
I have a multi applications which works with authenticated users.
All these applications can be deployed together for differents clients but with the same user database.
For example a chain of hotels.
User's roles informations are available in a header in each request.
For example a manager has full access in his own hotel but only read access in another hotel.
Ex:
{
["organization":"paris","roles":[ADMIN,ROOT]],
["organization":"london","roles":[READ]]
}
How can I handle many levels of roles by organizations?
I read some documentation in the symfony about voters and roles but nothing about roles in a kind of groups.
Voter is the way to go
// src/Security/PostVoter.php
namespace App\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class OrganisationVoter extends Voter
{
// these strings are just invented: you can use anything
const READ= 'READ';
const EDIT = 'EDIT ';
protected function supports($attribute, $subject); bool //todo
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
// [...] check class like documentation
$organisation= $subject;
switch ($attribute) {
case self::READ:
return $this->canView($organisation, $user);
case self::EDIT:
return $this->canEdit($organisation, $user);
}
}
private function canView(Organisation $organisation, User $user)
{
//here your logic if your user has the same organisation
}
private function canEdit(Organisation $organisation, User $user)
{
//here your logic if your user has the same organisation than the one in parameter and the good level of right (admin, root)
}
}
Then in your controller (or twig or wherever)
if ($this->security->isGranted(OrganisationVoter::EDIT, $organisation)) {
return true;
}
What you describe has "attribute-based access control" written all over. abac helps you externalize / decouple authorization from the application / API you want to protect. This means you can develop functionality independently of the authorization logic.
There are a couple of standards out there - namely XACML and ALFA (abbreviated language for authorization).
This is what the architecture looks like:
the Policy Enforcement Point (PEP) intercepts the business flow and create an authorization request which it sends to the PDP
The Policy Decision Point (PDP) evaluates the incoming request against the policies it's been configured with. It eventually returns a decision to the PEP
The PDP may use Policy Information Points (PIP) to retrieve missing metadata (a user's department, role, location; a resource's department, owner...)
The previous answer forces you to implement a voter. That's very brittle and will require coding and updating it regularly as your requirements change. In ALFA, you don't need to do that. You simply write policies in plain old English that use the attributes you are interested in. For instance:
A user with role == "manager" can do action == "view" on object of type == "hotel"
A user with role == "manager" can do action == "edit" on object of type == "hotel" if hotel.owner == user.name
I need to change user role on the fly based on specific data stored in the session. So on each request the authorization systems can check if the user can access some resource. I don't want store roles in a database. The role would be data dependent.
For example, a user that is admin of a real state company can manage his agents and properties, but an agent can manage only properties assigned to him. Also a buyer can view data of properties that he has purchased.
Take a look at This blog post, it shows how you can add user dependent roles. You can modify the part where he actually sets the role name.
I would make a few modifications to this method though
class User implements UserInterface
{
public function getRoles()
{
return new UserDependentRole($this);
}
}
And in the UserDependentRole class, have this instead:
public function getRole()
{
$roles[] = 'ROLE_' . strtoupper($this->user->getUsername());
//... make an array of all the roles you want the user to have
return $roles;
}
I'm sure if you read the article you will figure out how to do it.
So I have an asp.net application (using MVC5, ASP 4.5, EF) deployed on Azure. The application allows users to register and login.
However, once logged in, anyone can see everyone else's data.
What is the best practice to isolate the data belonging to different users so that each user can only see the data he/she creates?
Another small question is how does Facebook separates its users' data?
Thanks
For every piece of data a user creates, store their user ID and only allow users to see data that has their user ID. A couple of examples:
SQL:
SELECT UserDataID, Value FROM UserData WHERE UserID = #UserID;
Pass in the user's id to the #UserID parameter.
LINQ:
using (var entityFrameworkContext = new MyDataEntities())
{
var currentUserData = entityFrameworkContext.UserData.Where(userData -> userData.UserID = currentUserID);
}
Where currentUserID could be the user name or ID from forms authentication, for example: HttpContext.Current.User.Identity.Name.
The way in which I accomplished this was by the following.
In your controller you will need to use
public ActionResult Index()
{
var currentUser = manager.FindById(User.Identity.GetUserId());
return View(db.ToDoes.ToList().Where(todo => todo.User.Id == currentUser.Id));
}
You can then also create an admin role which can then view all the details of users and return ToList(). You then might want to put an [Authorize] method on it to only allow Admins access.
[Authorize(Roles="Admin")]
public async Task<ActionResult> All()
{
return View(await db.ToDoes.ToListAsync());
}
I found the following project of great help in understanding. https://github.com/rustd/AspnetIdentitySample
Hope this is of some help
My web method returns object 'User' that has a lot of properties: Id, Nick, Email, FirstName, SecondName, etc...
[WebMethod]
public User GetUserById(int userId)
{
vfm_elita.elita_table.user.User user =
vfm_elita.elita_table.user.User.GetUserById(userId);
return user;
}
Is there any possibility to limit amount of properties returned? Or I should to create a separate class (UserForClientForParticular) that has only required properties?
Thanks.
P.S. Guess, my last idea will be the suggested answer :), but anyway, any thoughts are welcome
It's a good idea to use a data transfer object, specialized to expose only the properties that the client-side should know about. Alternatively, if you're prototyping, in a hurry, or don't want to create a DTO class for some other reason, you can use an anonymous type to pare down the response:
[WebMethod]
public object GetUserById(int userId)
{
vfm_elita.elita_table.user.User user =
vfm_elita.elita_table.user.User.GetUserById(userId);
// Will return something like {"Nick":"Encosia","FirstName":"Dave"}
return new { Nick = user.Nick, FirstName = user.FirstName };
}
You should always be very aware of what data you expose in your APIs, especially if there's a chance that they'll be consumed by external parties but even if they are only used internally. I would definitely recommend what you mentioned in your post and create a construct designed to expose only the data that is necessary in this context.
Update: also recommend taking a look at the AutoMapper project on codeplex that handles automatically mapping property values from one object (User) to another object (UserSummary).