A Simpler Interface to Fluidinfo Permissions

I’ve previously blogged at a high level about the marvel that is Fluidinfo’s permissions system (Permissions Worth Getting Excited About and The Permissions Sketch) and more recently went into some more detail (Permissions in Fluidinfo) and proposed a conceptual simplification.

For me, however, a key question remains: what is a reasonable way for a user to inspect, understand and modify those permissions?

At first glance, if we compare Fluidinfo’s permissions system to that of the Unix file system [1], it looks vastly more complicated, suggesting that me might need a completely different model. In fact, it looks very similar to the permission system on VMS, for those who remember it, which—like Fluidinfo—implemented full access-control lists (ACLs).

If we think of a Fluidinfo namespace as being like a directory (which it is) and a tag (an abstract tag, if you prefer) as being like a file, then this is how the two permissions systems line up:

  • In Unix, there are only three types of permissions—read (r), write (w) and execute (x). In Fluidinfo, both tags and namespaces have a single read permission [2], but tags have seven different write permissions in total. There is no real equivalent of Unix’s execute permission in Fluidinfo, but both namespaces and tags have a control permission; in fact, tags have two different control permissions. This is summarized in the table below (cribbed from the previous post):

  • In Fluidinfo, the permission on a tag or namespace has a policy, which is open (available) or closed (unavailable) and an exception list—a list of users for whom policy is reversed. In contrast, on Unix are there separate permissions for the owner of the file or directory, for a group, and for everyone (world).

    This isn’t as different as it sounds. For read properties, Fluidinfo’s default permission is

    policy: open; exceptions: []

    meaning that anyone can read the file. And for write properties, Fluidinfo’s default permission, for both tags and namespaces is

    policy: closed; exceptions: [njr]

    where njr is the owner of the file.

    The default Unix permission on a file, as listed by an ls -l command, is:

    -rw-r--r--

    which is also known as a 644 permission (of which more later). For a directory, Unix’s default permission is listed as

    drwxr-xr-x
    

    which is also known as a 755 permission (again, more later).

    The first character in the string is simply information about the kind of file (d for a directory, l for a symbolic link, - for a regular file and very occasionally s for a pure-executable file with the sticky bit set [3]).

    After that, each group of three characters represents the permissions for some set of users—first the owner, then the group, then everyone else (world). Within each three-character component, the first character is an r if read access is available, the second is w if write access is is Available and the third is x if execute access is available. (Execute access is permission to run an executable file; it is overloaded, in the case of directories, to control whether people may set their working directory to this location and list the contents of the directory; this is a strange detail.) Pictorially, then, we have:

So how of the difference is essential, and how much presentational?

The difference in granularity of write permissions is entirely real, and on occasion probably useful, but in the interests of simplicity, let’s ignore it for now. More precisely, given that in normal circumstances, all the write permissions are the same for any tag or namespace, let’s express the case in which all the write permissions are available as w, the case in which none are available as / and in those rare cases where some are available and some are not, lets use another symbol—/ to indicate some.

Similarly, let’s use the position that Unix uses for execute permission to indicate control permission with a c; as with multiple write permissions, we will list a c where all the relevant control permissions are available, a - where none of them are and a / where some are.

If we don’t worry too much about Unix groups and Fluidinfo exception lists (other than when they contain the owner) we can express Fluidinfo permissions in a way that aligns perfectly with familiar unix permissions. For a tag, it turns out that Fludinfo’s default permissions are:

-rwcr--r--

and for namspaces (cf. directories), they are:

nrwcr--r--

It will not have escaped your attention that these are Strikingly similar to those in the Unix case. (I am sorely tempted to use d to indicate a namespace, since namespaces are directories in all but name, but I’ve baited Terry enough recently.)

So all that leaves is Unix groups and Fluidinfo exception lists.

Well, they’re totally different, right?

Groups, ACLs and Exceptions

Until I started thinking carefully about Fluidinfo permissions, I had always thought that Unix groups were simpler and markedly less powerful than the sort of full access-control lists offered by the like of VMS (and Fluidinfo). I now believe the difference to be much smaller than I had believed.

Here’s the thing: a unix group is a set of users. Each file is associated with a single group (by default, a group containing all users). But each unix user can be a member of multiple groups.

So if we’re prepared to create enough groups, we can effectively implement something very close to full ACLs using groups. If we want to allow Alice, Bjørn and Cécile to access a file foo on Unix, we can create a group (perhaps called alice+bjørn+cécile) containing them, move the file into that group, and then use the group permissions to allow the access that we want.

With this realization, it seems that the level of control available with groups is almost exactly the same as with “full” ACLs.

From an ACL perspective, a group is just a shorthand for a named group of users for use with ACLs.

From a group perspective, an ACL is just a dynamic group.

The only significant difference is that ACls allow us to use a different group for different permissions on the same file or directory: so we could allow one group of users read access and another group write access, while denying both to the world. Although this is not an unimaginable case, it’s probably fairly rare.

With this perspective, we can now map the final part of Fluidinfo permissions onto a Unix-like permissions string. First let’s take the case where I’ve allowed Alice to write my rating tag.

Tag njr/rating:
  read policy: open; exceptions: []
  all write policies: closed; exceptions: [njr, alice]
  all control policies: closed; exceptions: [njr]
  ls -l njr/rating
  -rwcrw-r--   rating

Now let’s take the case where I’ve removed read permission from the world for my friends namespace but but allowed it for a group consisting of Alice,Bjørn and Cécile:

Namespace njr/friends:
  read policy: closed; exceptions: [njr, alice, bjørn, cécile]
  all write policies: closed; exceptions: [njr]
  all control policies: closed; exceptions: [njr]

“Ah,” you say, “but what if I want to know who is in the group?” Well, what does Unix do? It gives us a -g option on ls to list the group that the file is in. So if we take the idea of dynamic groups, we would have the following:

ls -g njr/rating
-rwcrw-r--   alice   rating
ls -g njr/friends
nrwcr-----   alice+bjørn+cécile   friends

So the mapping is essentially complete. There are corner cases—primarily the one discussed above, where full ACLs allow different groups for read and write permissions—but I’m sure this will cover the vast bulk of real-world cases. This is what we have ended up with.

If the full detail were really needed, I would be tempted to have a -L flag to expand the write permissions (and conceivably the control permission) to use the names in the alternative naming scheme I proposed in the last post. Again, I reproduce the key table here:

So if (for reasons I find hard to imagine) I’d allowed Alice, Bjórn and Cécile to tag and untag objects with my njr/friends/phone tag, but not to delete the tag itself (the abstract tag and all its occurrences) or to change its description, then we might get this:

Tag njr/friends/phone:
  read policy: closed exceptions: [njr, alice, bjørn, cécile]
  tag & untag write policies: closed exceptions: [njr, alice, bjørn, cécile]
  metadata and delete write policies: closed exceptions: [njr]
  all control policies: closed exceptions: [njr]
  ls -L njr/friends
  n rwc r[-tu-]- ---   alice+bjørn+cécile   friends

where I would expand only permissions where a simple r or w would not be accurate and have added some spaces to make the user groups stand out more clearly. If the exception lists were different for different permissions, I’d probably give up and actually show the Fluidinfo style permissions.

Coming soon to an fdb near you . . .

I hope I’ve convinced you in this post that mapping full Fluidinfo ACLs to a Unix-style reporting system for permissions is not nearly such a hopeless task as it might first appear.

The reason I want to do this is not because Unix is the be-all and end-all in user interfaces (!), but because it is familiar (at least to many) and proven and has conventions that I think will make it much easier for people to understand what’s going on. It also suggests a way forward on setting permissions.

The next thing I plan to add to fdb is an ls (list sorted) command exactly as described above. In fact, most of it is already implemented (thought not yet pushed to GitHub).

After that (not implemented) I plan to add the equivalent of chmod and chgrp for setting permissions and changing groups (exception lists) respectively.

I haven’t really thought through what these should be called or what their syntaxes should be, but the cases I most care about supporting easily are the ones that I think will be common. I will probably just support numeric specifications (explained below) at first, and then add the g-r-style modifiers later if anyone demands them. (Personally, I never use them.) Key examples would include:

  • Making a tag or namespace njr/foo completely private

    chmod 700 njr/foo
  • Making a tag or namespace readable and only by a group (plus me):

    chgrp alice+bjørn+cécile njr/foo
    chmod 740 njr/foo

    (The order of users wouldn’t matter; it’s a name specifying a virtual group, not a real group name.)

  • Making a tag or namespace writable by some group (plus me)

    chgrp alice+bjørn+cécile njr/foo
    chmod 764 njr/foo

Here, following Unix’s lead, the permissions for each class of user (owner, group, world) are expressed as a 3-bit number where the first (most significant) bit represents read permission, the middle bit represents write permission and the last (least significant) bit represents control permission. So rwc becomes 4 + 2 + 1 = 7, rw- becomes 4 + 2 = 6, r-- becomes 4 and --- becomes 0. Other possibilities exist, but are rarely used. (The James Bond setting, 007, allows anyone in the world except the onwer to read, write and control the tag or namespace; I’ve never seen it used on Unix or in Fluidinfo.)

If I can think of some reasonable shorthands with less intimidating commands, I might make those available too. Perhaps something like:

perms private njr/foo                    --- Set to 700
perms group-write alice+bjørn+cécile foo --- Set to .6.
perms group-read alice+bjørn+cécile foo  --- Set to .4.
perms default njr/foo                    --- Set back to default (normally 744).

Footnotes

[1]I am using “Unix” here to refer at least to any version of Unix and broadly also to cover Linux. I think most of what I say also applies to Windows, but having only really Windows for a painful 20 years of my life, I never really understood Windows permissions; in fact, the only way I ever succeeded in changing them was using Cygwin (which made them look like Unix permissions) or through python, which did the same. So maybe everything I’m saying applies to all Posix systems. I’m not sure.
[2]Fluidinfo calls the ability to read the contents of a namespace list permission, but in the simplification I proposed, it becomes simply read.
[3]If you don’t know what a sticky bit is, it’s a bit of Unix archania that you probably don’t need to know, but which Wikipedia will happily tell you all about. I believe sticky bits really do only apply to proper Unixes, not Linux/generic Posix systems, where I suspect they are not missed.