I have objects in my system with relations to owners and collaborators and now I need to add permissions on viewing these objects. Currently if the user is the owner or listed as a collaborator they can see the object. I have that logic encapsulated already but it seems the "proper" way would be to use a row level permission system and assign these users permissions. However that becomes more complicated when it comes to assigning and removing permissions and also makes viewing more expensive as it has to look up permissions in the database rather then relying on data that is already being accessed. I have been looking into django-guardian and it seems like overkill right now.
Check out django-logical-rules. Rules are written in python and you can pass existing objects to a rule, so their isn't necessarily a db hit... although I would recommend caching. Rules can be easily integrated with generic views and accessible with a template tag.
Related
I am writing a C++ application with a postgresql 9.2 database backend. It is an accounting software. It is a muti user application with privilege separation features.
I need help in implementing the user account system. The privileges for users need not be mutually exclusive. Should I implement it at the application level, or at the database level?
The company is not very large at present. Assume about 15-20 offices with an average of 10 program users per office.
Can I make use of the roles in postgres to implement this? Will it become too tedious, unmanageable or are there some flaws in such an approach?
If I go via the application route, how do I store the set of privileges a user has? Will a binary string suffice? What if there are additional privileges later, how can I incorporate them? What do I need to do to ensure that there are no security issues? And in such an approach I am assuming the application connects with the privileges required for the most privileged user.
Some combination of the two methods? Or something entirely different?
All suggestions and arguments are welcome.
Never provide authorization from a client application, which is run on uncontrolled environment. And every device, that a user has physical access to, is an uncontrolled environment. This is security through obscurity — a user can simply use a debugger to get a database access credentials from client program memory and just use psql to do anything.
Use roles.
When I was developing an C++/PostgreSQL desktop application I've chosen to disallow all users access to modify all tables and I've created an API using Pl/PgSQL functions with VOLATILE SECURITY DEFINER options. But I think it wasn't a best approach, as it's not natural and error prone to use for example:
select add_person(?,?,?,?,?,?,?,?,?,?,?,?);
I think a better way would be to allow modifications to tables which a user needs to modify and, when needed, enforce authorization using BEFORE triggers, which would throw an error when current_user does not belong to a proper role.
But remember to use set search_path=... option in all functions that have anything to do with security.
If you want to authorize read-only access to some tables then it gets even more complicated. Either you'd need to disable select privilege for these tables and create API using security definer functions for accessing all data. This would be a monster size API, extremely ugly and extremely fragile. Or you'd need to disable select privilege for these tables and create views for them using create view with (security_barrier). Also not pretty.
Lets say I have django.contrib.sessions.middleware.SessionMiddleware installed in django and I'm using SessionAuthentication class for API authentication in tastypie. Within a session I'm doing some changes in models through my API and after that I want to roll back. Can I do it through tastypie? If yes, what method should I execute? I can't find such a method in tastypie docs. Do you have any working example of that?
Django supports database transactions, which will commit multiple state changes atomically. (Documentation...)
It is unclear in your question how you want to trigger the rollback. One option is to use request transactions, which will rollback if an unhandled exception is issued by the view function. If you want more fine grained control, familiarize yourself with the options in the linked-to documentation. For example, you may explicitly create a transaction and then roll it back inside your view.
With respect to Tastypie, you may need to place your transaction management inside the appropriate method on the Resource interface.
I hope this gives you some pointers. Please update your question with more details if necessary.
So you want to commit changes to your models to the database, and then roll them back on a future request? That's not something that TastyPie supports (or, for that matter, Django or SQL). It's not really possible to do a clean rollback like that, considering other requests could have interacted with/changed/ built relationships with those objects in the mean time.
The best solution would probably be to integrate something like Reversion that would allow you to restore objects to a previous state.
If you want to be able to roll back all of the operations during a session, you'd probably need to keep track of the session start time and the list of objects that had been changed. If you wanted to do a rollback, you'd just have to iterate over that list and invoke reversion's revert method, like
reversion.get_for_date(your_model, session_start_datetime).revert()
However, again, that will also roll back any changes any other users have made in the same time frame, but that will be the case for any solution to this requirement.
currently I am looking implementing access control in Django. I've read about the built-in permission, but it does not takes care per object basis. For example, I want permissions like "Only the creator can delete his own items". So I read about django-guardian. Then again, after thinking about it, it may be difficult to manage and check if constraints ever change.
I look at the next popular permission management app called django-rules. This seems to suit what I require. However, I believe django-rules requires a model instance to be involved (hence object level) i.e if I require a simple view like "member's area", it does not perform this function.
This has led me to think about using both the contrib's permission for the latter scenarios and django-rules for the former. My question here, is how easy will it be to manage both permission frameworks?. For instance, I have different groups of users. I am worried about overlapping scenarios whereby the admin added a particular permission in the admin system (to allow access to a view), thinking that should suffice but turns out to be bounded by constraints set by the rules.
I believe this is a common case and I humbly seek your advices and recommendations based on your experiences.
If you're doing this through Django admin site, you can override methods such as has_delete_permission(). These get request and object as arguments, so you can use it to set up rules like "User X can delete only his own objects".
Background
I have a backoffice that manages information from various sources. Part of the information is in a database that the backoffice can access directly, and part of it is managed by accessing web services. Such services usually provides CRUD operations plus paged searches.
There is an access control system that determines what actions a user is allowed to perform. The decision of whether the user can perform some action is defined by authorization rules that depend on the underlying data model. E.g. there is a rule that allows a user to edit a resource if she is the owner of that resource, where the owner is a column in the resources table. There are other rules such as "a user can edit a resource if that resource belongs to an organization and the user is a member of that organization".
This approach works well when the domain model is directly available to the access control system. Its main advantage is that it avoids replicating information that is already present in the domain model.
When the data to be manipulated comes from a Web service, this approach starts causing problems. I can see various approaches that I will discuss below.
Implementing the access control in the service
This approach seems natural, because otherwise someone could bypass access control by calling the service directly. The problem is that the backoffice has no way to know what actions are available to the user on a particular entity. Because of that, it is not possible to disable options that are unavailable to the user, such as an "edit" button.
One could add additional operations to the service to retrieve the authorized actions on a particular entity, but it seems that we would be handling multiple responsibilities to the service.
Implementing the access control in the backoffice
Assuming that the service trusts the backoffice application, one could decide to implement the access control in the backoffice. This seems to solve the issue of knowing which actions are available to the user. The main issue with this approach is that it is no longer possible to perform paged searches because the service will now return every entity that matches, instead of entities that match and that the user is also authorized to see.
Implementing a centralized access control service
If access control was centralized in a single service, everybody would be able to use it to consult access rights on specific entities. However, we would lose the ability to use the domain model to implement the access control rules. There is also a performance issue with this approach, because in order to return lists of search results that contain only the authorized results, there is no way to filter the database query with the access control rules. One has to perform the filtering in memory after retrieving all of the search results.
Conclusion
I am now stuck because none of the above solutions is satisfactory. What other approaches can be used to solve this problem? Are there ways to work around the limitations of the approaches I proposed?
One could add additional operations to the service to retrieve the
authorized actions on a particular entity, but it seems that we would
be handling multiple responsibilities to the service.
Not really. Return a flags field/property from the web service for each record/object that can then be used to pretty up the UI based on what the user can do. The flags are based off the same information that is used for access control that the service is accessing anyway. This also makes the service able to support a browser based AJAX access method and skip the backoffice part in the future for added flexibility.
Distinguish between the components of your access control system and implement each where it makes sense.
Access to specific search results in a list should be implemented by the service that reads the results, and the user interface never needs to know about the results the user doesn't have access to. If the user may or may not edit or interact in other ways with data the user is allowed to see, the service should return that data with flags indicating what the user may do, and the user interface should reflect those flags. Service implementing those interactions should not trust the user interface, it should validate the user has access when the service is called. You may have to implement the access control logic in multiple database queries.
Access to general functionality the user may or may not have access to independant of data should again be controlled by the service implementing that functionality. That service should compute access through a module that is also exposed as a service so that the UI can respect the access rules and not try to call services the user does not have access to.
I understand my response is very late - 3 years late. It's worth shedding some new light on an age-old problem. Back in 2011, access-control was not as mature as it is today. In particular, there is a new model, abac along with a standard implementation, xacml which make centralized authorization possible.
In the OP's question, the OP writes the following re centralized access control:
Implementing a centralized access control service
If access control was centralized in a single service, everybody would be able to use it to consult access rights on specific entities. However, we would lose the ability to use the domain model to implement the access control rules. There is also a performance issue with this approach, because in order to return lists of search results that contain only the authorized results, there is no way to filter the database query with the access control rules. One has to perform the filtering in memory after retrieving all of the search results.
The drawbacks that the OP mentions may have been true in a home-grown access control system, in RBAC, or in ACL. But they are no longer true in abac and xacml. Let's take them one by one.
The ability to use the domain model to implement the access control rules
With attribute-based access control (abac) and the eXtensible Access Control Markup Language (xacml), it is possible to use the domain model and its properties (or attributes) to write access control policies. For instance, if the use case is that of a doctor wishing to view medical records, the domain model would define the Doctor entity with its properties (location, unit, and so on) as well as the Medical Record entity. A rule in XACML could look as follows:
A user with the role==doctor can do the action==view on an object of type==medical record if and only if the doctor.location==medicalRecord.location.
A user with the role==doctor can do the action==edit on an object of type==medical record if and only if the doctor.id==medicalRecord.assignedDoctor.id
One of the key benefits of XACML is precisely to mirror closely the business logic and the domain model of your applications.
Performance issue - the ability to filter items from a db
In the past, it was indeed impossible to create filter expressions. This meant that, as the OP points out, one would have to retrieve all the data first and then filter the data. That would be an expensive task. Now, with XACML, it is possible to achieve reverse querying. The ability to run a reverse query is to create a question of the type "What medical record can Alice view?" instead of the traditional binary question "Can Alice view medical records #123?".
The response of a reverse query is a filter condition which can be converted into a SQL statement, for instance in this scenario SELECT id FROM medicalRecords WHERE location=Chicago assuming of course that the doctor is based in Chicago.
What does the architecture look like?
One of the key benefits of a centralized access control service (also known as externalized authorization) is that you can apply the same consistent authorization logic to your presentation tier, business tier, APIs, web services, and even databases.
I am developing a Django web application with a suite of steel design tools for structural engineers. There will be a database table of inputs for each design tool, and each row of each table will correspond to a particular design condition to be "solved." The users may work solely or in groups. Each user needs to have ongoing access to his own work so that designs can be refined, copied and adapted, and so that reports can be created whenever convenient, usually at the end of a project when hard copy documentation will be needed. The database contents must then be available over any number of sessions occurring over periods measured in months or even years for a given design project.
When there is a group of users, typically all associated with a given design office, it will probably be acceptable for them all to have joint and mutual access to each other's work. The application supports routine engineering production activities, not innovative intellectual property work, and in-house privacy is not the norm in the industry anyway. However, the work absolutely must be shielded from prying eyes outside of the group. Ideally, each group would have one or more superusers authorized to police the membership of the group. Probably the main tool they would need would be the ability to remove a member from the group, discontinuing his access privileges. This would be a user group superuser and would not be the same as a superuser on the site side.
For convenient access, each row of each database table will be associated with a project number/project name pair that will be unique for a given company deploying a user or user group. A different company could easily choose to use a duplicate project number, and even could choose a duplicate project name, so discriminating exactly which database rows belong to a given user (or group) will probably have to be tracked in a separate related "ownership list" table for each user (or group).
It is anticipated (hoped) that, eventually, several hundred users (or user groups) associated with different (and often competing) companies will solve tens of thousands of design conditions for thousands of projects using these tools.
So, here are my questions:
First, is there any point in trying to salvage much of anything from the Django contrib.auth code? As I perceive it, contrib.auth is designed for authentication and access control that is suitable for the blogosphere and web journalism, but that doesn't support fine-grained control of access to "content."
Second, is there any available template, pattern, example, strategy or design advice I could apply to this problem?
django-authority: Documentation, code on GitHub