I've been thinking about security models lately, as I'm presented with creating one for a CMS I've been working on. But I don't feel like I have a lot of good models to work off of.
The traditional Unix model has some positive points. Quick review: each object has an owner and a group owner, and you can set permissions for the owner, any member of the group, and everyone else. The positive is that this system is easy to implement, easy to understand, and easy to audit. It's very concrete, and it can be presented quite succinctly in the output of ls -l.
But there's lots of negatives too. It's obviously not very flexible -- just one owner, and one group owner. But there's also lots of other confusions. How does the container (directory) relate to the object (file)? What permissions do new objects get? There's several things that interact here -- sticky bits, imask, and probably other things I'm not even aware of. And in the end this still isn't expressive enough -- ownership and permission is frequently messed up (at least where users are involved).
An alternative is Access Control Lists (ACLs). These are pretty much like traditional Unix permissions, only where's there's just one owner and group there, you can have lists of them with ACLs. This can get you out of some binds, but does it really help things that much? Where Unix permissions can be unnecessarily eclectic, at least they are easy to review -- ACLs are dense and prone to organic growth. They are difficult to audit, and it is difficult to really have a sense of the overall permissions for a system -- you only can know the permissions for one file at a time.
And just like Unix permissions, it's hard to understand future objects. Where do new files' permissions come from? The container, the creating user, the file type, the creating software? And how do you change that policy?
Neither system is very useful when translated to a more general system like a CMS. Filesystems are easy, at least, because the set of operations is so small -- you create, read, and write. The set of permissions for a folder in a Zope instance has 88 different actions, times how ever many roles you have, with the option of inheriting from the container (so you have to look through a bunch of different screens to figure out what the actual permissions for one location is). This is not a setup that encourages good security -- it's essentially an ACL, except where only groups are assigned permissions, never individual users. (But at least the permissions of new objects are easy to ascertain, as they are all dynamically inherited)
I think object-oriented permission schemes are much better. By object-oriented I mean: expressed with code, not data. You don't have data about objects, you ask objects about themselves; you don't do things with objects, you ask objects to do things for themselves. It's all much more ad hoc as a result, and likely requires real programming to make changes to the system. But I would say that a few lines of code are superior to a big table of values -- the heterogeneous structures we create on demand are more expressive and less prone to bugs than are larger, more general homogeneous data structures. I can express the typical Zope security table with only a couple lines of (pseudo-) code:
class ... def permitted(self, user, action): return self.container.permitted(user, action)I.e., acquire all permissions from your container. When using these kind of dynamic permissions, it's possible to be so much more expressive, because you have access to the eclectic data that is relevant to each object. For instance, you might allow a user to modify, in a limited manner, documents that point to a document which they have control over. Or you can introduce explicit delegation of permissions in certain contexts. For any domain there's a large number of potential, specific rules that might govern permissions.
Unfortunately, having chosen this ad hoc route, you've given yourself so many degrees of freedom that it's hard to figure out which way to go. Sure, that permitted function seemed easy enough. But a real system needs to know more than that -- for an action, what are the users that can perform it? For a user and action, what are the objects for which they are permitted? And (for symmetry) for a user and object, what actions are permitted? How do you present an interface for changing particulars of the permissions? As you change those functions, how do you update objects, how do you delegate responsibility between objects? These are all typical programming questions, and their solutions are even that particular to security, but they are also questions that are often answered incorrectly and refactoring permissions can seem as daunting as writing them in the first place. It seems like there's not enough precedent to serve as a guide, there's not enough examples of transparent yet powerful and flexible systems.
While I don't know the underlying code, I suspect Zope is as general as what I've described. But presented with this freedom, most programmers of subsystems for Zope have simply used the tabular system that seems so straight forward, if not elegant. It's easier to build an ACL instead of finding something domain-specific.
Are there systems out there worth inspection and immitation? Please tell, be they databases, filesystems, client/server applications, web applications, or anything else.
What you are looking for are described in the literature as "capabilities." Think of them as ACLs with real meaning. There is a Java variant called E that was developed by a company I used to work for (before the company blew up the lang was open-sourced) which was a capability-secure version of Java. One of the members of the E inner circle is Ka-Ping Yee (author of various PEPs) and his continued involvement with E gives me hope that one day it might make its way into Python is some shape, perhaps as a replacement for the recently nuked "safe" execution modules.
One thing that the E folks have done a lot of work on is dealing with UI issues and programming issues related to capabilities and the first few steps toward making this whole process a bit easier for the programmer. Be warned though, this group has been talking about this stuff for many years and has its own internal language to describe programming structures and processes that seems a bit opaque until you actually get your mind wrapped around the capability paradigm.# Jim McCoy
I'm curious - is this CMS you're developing based on Webware (or you're simplified version of Webware)? Is it for work/fun/both?# Joel Lawhead
It's actually written in Zope, which is what I've been doing a lot of my professional work in lately.# Ian Bicking
Jim: There was a good, ad-hoc roundtable discussion at PyCon DC 2003 about capabilities, in which Ka-Ping Yee participated (drove, really :-) ) to help get other people up to speed on the basic notions. I think your hopes about seeing capabilities in Python are definitely justified.
A google search for "python capabilities" yields several meaty threads from python-dev and the like, as well.
Ian: To follow up on Jim's comments, capabilities are a very powerful mechanism for managing access to resources (whether the resources are objects, methods, what have you). It's not clear that you can make them completely safe within Python right now if you allow arbitrary code execution (hence the removal of the restricted execution tools), but if you're controlling the code side of things, and you're mainly looking for internal mechanisms of managing access, take a look.
You should also check out EROS, a capabilities-based operating system. There are many good design notes and background papers on capabilities-based security there.# Tripp Lilley
there are also novell's trustees which offer another interesting approach on filesystem security. there's a patch for linux which allows you to use trustee style security rules. the url is http://trustees.sourceforge.net/
thx for good solution :>
the patch is a little bit outdated, but applies well to newer kernel versions (except of some parts which need to be merged manually).