I try to manage the access rights for users to edit or view different articles.
Articles can be created dynamically and the rights should be editable for every article.
In my case, I have a User object and multiple other objects (Article, and more...).
I need to check if a User can read or write any kind of object.
I actually see there is a method Voters, but they only can manage User groups?
Can somebody help me?
A Voter can decide almost anything - usually it's based on a user's permission, but it doesn't have to be - I've used one as a 'feature flag' check, with a value fetched from a configuration, or database entry to show something - or not, as an example.
The page on voters has an example on viewing, or editing a database record (a Post entity, via a $this->denyAccessUnlessGranted('edit', $post);.
In your instance, the voter would be passed the 'attribute', the object (Article, etc) you want to check on, and gets the current user from a service. If that user has the appropriate permission to read/edit/delete the Article or other object, it returns true.
Hello guys,
I started to work on securing my Firebase. I have a location containing a list of events :
events:
$event1: {
name: test
...
}
$event2: {
name: test2
...
}
In my app, I let the user add events using their name. For that, after the user validates his input (eventName), I'm looking if that name exists using
ref.child("events").orderByChild("name").equalTo(eventName)
And if so, I will add it to the list of user's events. My issue is with security. If I define security rules like so :
"events": {
"$eventId": {
".read": "auth != null"
}
}
Then it fails - it's completely expected since "events" location, which is targeted by the Firebase reference, has no "read" rule. The problem is, I don't want to open the "events" location for read by all connected users, since events are private and must be shared directly by their name.
So, since this name must be unique, I could use it as the event object key in place of the Firebase generated key (I currently use .push() when a new event is created to add it to the list, Firebase generates me the key), but I really like the way it is now. So I ask before changing : is there another way to reach what I'm aiming to do ?
Thanks a lot ahead.
The reason things don't work as expected here is that security rules are not filters. Rules are applied in an atomic manner. That means that a read or write operation is failed immediately if there isn't a rule at that location or at a parent location that grants access. Even if every child path is accessible, reading at the parent location will fail completely.
So, you would only be able to read from the /events/ node if you can read every child of that node. So if you are not logged in or you are not logged in with the correct user, the read will fail.
To accomplish what you want, you should add an /events/ node to each user in your /users/ node which just list the eventId for each event they are a part of. Then you don't need you event query and can instead just easily get a users events by doing a read at /users/$uid/events/. Then you can look up the event details from the /events/$eventId/ node and avoid any reads at the top-level /events/ node which is disallowed by security rules.
Generally when implementing some sort of role based access control, we have the following well-known concepts:
Role
User
Permission
And users would be assigned to roles each of which have a set of permissions (to perform an operation / access a resource etc).
So users gain permissions to perform operations by being assigned to one or more roles (which have been assigned a set of permissions).
In any given application, permissions are defined at compile time since the code actually enforces the permissions at various places where access to resources .
My thinking is that if the set of possible permissions/operations changes – it requires changes to the code and recompilation any way, so having a lookup/reference table in the database won’t really provide any value beyond the fact that a db admin could do a quick sql query to list all permissions used by an app.
Yet most applications I’ve seen create a lookup table for the permissions and -also- map it to a enum in the code.
Given this, is there any reason to actually have a database table representing the list of possible permissions (other than the fact that it is probably easier for some to look in the db as opposed to digging into the code to find the list/enum of permissions)?
Checklist:
1) Do you need to make changes while the website is online, without downtime?
2) Will you be using built-in role/membership provider?
3) You want to use attributes (like mvc [Authorize]) etc?
4) You want to allow users to programatically change permissions/roles?
Any of the above means you have to store the info on DB.
For smaller scale apps I prefer to just create some static methods that also use some kind of inheritance, ie:
isadmin()
{
if (usernameArray.Contains[currentname])
return true;
[...]
}
ispublisher()
{
if (isadmin()) return true;
[...]
}
And a table with permissions for each user pseudo-class.
Update: DB schema for specific access: (* is key, & is foreign key)
Users:
Username *
[...]
UserClasses (EG: admin...)
ID *
description
AccessTypes (EG: can delete)
ID *
description
UserClassesAssign
classid *&
username *&
AccessPerClass
accessid *&
classid *&
So anytime you want to see if 'username' is able to 'CanDelete' you have to check if the User 'username' is linked to any classes that are linked to the access 'CanDelete', and these links can of course change during runtime
Q1 - I’m not sure I understand why we should prefer to use PrincipalPermission.Union() ( or PrincipalPermission.Intersect() ) instead of IsInRole()? If anything, calling IsInRole() several times requires less code than creating multiple PrincipalPermission objects and merging them into one via Union() ( or Intersect() )?
Q2 - One constructor overload of PrincipalPermission object also specifies a IsAuthenticated flag that tells Demand() to verify if user is authenticated. Wouldn’t using that flag only be useful in situations where first two parameters ( name and role ) are both null?
thanx
Q1. - RE: PrincipalPermission methods vs. IPrincipal.IsInRole(..)
The two function calls make a PrincipalPermission that has the union or intersection of the roles you give it. Thus you end up with a principal that has a very specific set of demands, which you can then call IsInRole() upon. Note that doing this will hit your role provider which may be an SQL server or the active directory and thus have latency involved, so you don't want to do it all the time.
Q2. - RE: PrincipalPermission authentication
Authenticated indicates that the user is logged in against your provider. You may want this if you need only auditing on your application, confirming the user is logged in to your role provider will mean that you can log who they are etc.
You are correct in saying it's only useful where you don't care about who the user is, only that they are logged in.
I have a classic 3-tier ASP.Net 3.5 web application with forms that display business objects and allow them to be edited. Controls on the form correspond to a property of the underlying business object. The user will have read/write, readonly, or no access to the various controls depending on his/her role. Very conventional stuff.
My question is: what is the object-oriented best practice for coding this? Is there anything more elegant than wrapping each control in a test for the user's role and setting its Visible and Enabled properties?
Thanks
You'll want to drive this off of data, trust me. You'll need a lot of tables to do it right, but it is so worth it in the end. Having to crack open code and edit a bunch of if-statements every time the business wants to change permissions is a killer.
You'll want a table for your main high-level types, things you probably already have business object clases for. Then a table for each status of them. Then a table for the fields of these classes. Then a table for user roles (admin, guest, etc.) Finally a table for the permissions themselves. This table will have columns for business class, status, field, user role, and then what permission they have. For permissions I would go with one field and use an enum: Hidden, ReadOnly, Editable, and Required. Required implies Editable. Anything but Hidden implies Visible. Finally put a Priority column on this table to control which permission is used when more than one might apply.
You fill out this table with various combinations of class, status, field, role, and permission. If a value is null then it applies to all possible values. So you don't need a trillion rows to cover all your bases. For example, 99% of the time, Guest users are read-only users. So you can put a single entry in the table with only the Guest role specified, everything else is null, and set it's Priority nice and high, and set the permission to Read Only. Now for all classes, all statuses, all fields, if the user is a Guest, they will have Read Only permission.
I added status to your list of concerns because in my experience, business all the time wants to constrain things by an object's status. So maybe users can edit an item's name while it is in Draft status, for example, but once it is in Posted status, the name is no longer editable. That is really common in my experience.
You'd want to bring this table into memory and store it in the app's cache, because it's not going to change very often, if ever, unless you do a whole new version.
Now the above is going to handle 90% of your needs, I suspect.
One area that will have to be handled in code, unless you want to get really fancy, is the cases where a user's permission is determined in part by the value of fields in the object itself. So say you have a Project class, which has a Project Manager class. Now the Percent Complete field of the class is basically read-only for everybody, except the Project Manager. How are you going to handle that? You'll need to provide a way to incorporate specific instances of a class into the decision making process. I do this in code.
To work properly, I have found that access levels should be in this increasing order:
NONE, VIEW, REQUIRED, EDIT.
Note that REQUIRED is NOT the top level as you may think it would be since EDIT (both populate & de-populate permission) is a greater privilege than REQUIRED (populate-only permission).
The enum would look like this:
/** NO permissions.
* Presentation: "hidden"
* Database: "no access"
*/
NONE(0),
/** VIEW permissions.
* Presentation: "read-only"
* Database: "read access"
*/
VIEW(1),
/** VIEW and POPULATE permissions.
* Presentation: "required/highlighted"
* Database: "non-null"
*/
REQUIRED(2),
/** VIEW, POPULATE, and DEPOPULATE permissions.
* Presentation: "editable"
* Database: "nullable"
*/
EDIT(3);
From the bottom layer (database constraints), create a map of fields-to-access. This map then gets updated (further restrained) at the next layer up (business rules + user permissions). Finally, the top layer (presentation rules) can then further restrain the map again if desired.
Important: The map must be wrapped so that it only allows access to be decreased with any subsequent update. Updates which attempt to increase access should just be ignored without triggering any error. This is because it should act like a voting system on what the access should look like. In essence, the subsequent layering of access levels as mentioned above can happen in any order since it will result in an access-level low-water-mark for each field once all layers have voted.
Ramifications:
1) The presentation layer CAN hide a field (set access to NONE) for a database-specified read-only (VIEW) field.
2) The presentation layer CANNOT display a field when the business rules say that the user does not have at least VIEW access.
3) The presentation layer CANNOT move a field's access up to "editable" (nullable) if the database says it's only "required" (non-nullable).
Note: The presentation layer should be made (custom display tags) to render the fields by reading the access map without the need for any "if" statements.
The same access map that is used for setting up the display can also be using during the submit validations. A generic validator can be written to read any form and its access map to ensure that all the rules have been followed.
I have often found that this is really the only real easy and understandable way to do it, as your interface needs to modify based on the information and level of editing that they can complete.
I do find typically though that depending on the needs, you can interject the "cannot edit" information by passing role information to the business level if you have plans to move to different presentation levels. but this adds complexity, and if you are only building for one interface it would most likely be overkill
For the website menus we can have different menus based on users role by using the Sitemaps. For controls like Buttons we will have to hide them using their Visible property. I think a good idea will be to create a server control (Button) and expose the Role property. This will hide the Button if the user is not in the correct role.
My first instinct for doing this in a more OO way would be to handle your roles and their implementations for this purpose (control permissions read/write/etc) is to use the abstract factory pattern for your roles. I will be happy to explain the ins and outs of what I am talking about if you'd like but there are probably 900 examples on the web. Here is one link (disclaimer: it's my blog but it does happen to talk to using abstract factory for roles specifically)
Using something like this you could then use a number of methods to display the correct controls for each of your business object properties with the correct attributes (read/write/hidden/displayed/etc).