Securing shell-fish with fish: Even More on Fluidinfo PermissionsΒΆ

I mentioned in my last post that I’ve extended the range of permissions that can be set with the perms command to cover the whole gamut. Here, I’ll describe this in the context of showing how I have set up permissions for the fish user to make them suitable for use with the online version of fishshell-fish.

My goal was this. Shell-fish, the online version of fish, allows users to log in with their Google account and effectively link it to one or more Fluidinfo accounts. Users who do this can use fish to perform arbitrary Fluidinfo operations using their own tags. But I also wanted to allow users to try out Fluidinfo and fish without setting up an account. Initially, I did this using the Fluidinfo test user, but that’s probably not a good long-term solution. What I’d prefer to do is to provide a locked down account that anyone can use for certain things—not only for reading but also to try out tagging. The process of locking down a Fluidinfo account is also useful as an illustration of the extended perms command in fish, so that is the subject of this post.

I created the Fluidinfo fish user and switched to it in fish.

$ fish su fish
Credentials set to user fish.
$ fish ls -ld fish
nrwcr--r--   fish/

As you can see the permissions on fish’s namespace are the defaults, with the user having read, write and control permission, and everyone else having read only. (See this post or the fish documentation for the ls command).

The first thing I wanted to do was to transfer control permission from the fish user to me (njr) so that a user of Shell-Fish can’t do arbitrary things. This wasn’t possible with the original perms command, but I’ve added three new forms of the command, each of which follows the general template:

fish perms perms-class [open|closed] [except list+of+users] list of tags or namespaces

where perms-class is one of read, write or control. This simply lets the user set the explicit FLuidinfo permissions, as open or closed, with an optional exception list. The exception list is specfied as a list of users, separated by + signs. The command only changes the permissions class specified and changes all the permissions in that class for the tags or namespaces given. So valid examples operating on a tag fish/rating and a namespace fish/private include:

fish perms read closed except fish fish/rating fish/private
fish perms write closed fish/rating fish/private
fish perms control closed except fish+njr fish/rating fish/private

To transfer the control permissions to njr for the top-level fish namespace, I used the command (still as the fish user at this point):

$ fish perms -f control closed except njr fish

The only extra thing to notice here is the -f flag, which forces fish to make a change it would otherwise resist. Any change to permissions that results in the owner of a tag or namespace not having control permissions falls into this category, and since this is usually undesirable, fish requires the -f flag to force this to happen. (Tranferring permission to njr is, of course, irreversable for fish.)

Having made this change, if we repeat the ls command we see this:

fish ls -ld fish
(denied)    fish/

Fluidinfo allows only users with control permission to see the permissions on tags and namespaces, so the fish user can no longer see them. (I suppose this is slightly odd: it means that you can’t even see that you have write permission if you don’t have control permission. But that’s not a huge problem.)

Let’s switch to njr and try.

$ fish su njr
Credentials set to user njr.
$ fish ls -ld fish
nrw-r-cr--   fish/

This is as expected. The owner—fish—no longer has control permission on the fish namespace, but someone in a group does. We know that someone is njr. (We could verify this with ls -L, as we will after making some more changes.)

So far so good.

In terms of writing, my initial idea is to provide a set tags with single-letter names (a to z) in fish‘s top-level namespace that fish can write, but not to allow other tags or namespace to be written.

First, let’s create those tags as the fish user.

$ fish su fish
Credentials set to user fish.
$ fish -U touch a b c d e f g h i j k l m n o p q r s t u v w x y z

The touch command on a non-existent tag creates the tag, and the -U says use Unix-style paths, i.e. assume they’re in the authenticated user’s namespace unless introduced with a leading /. So this creates the 26 single-letter tags I want.

Next, we need to remove write permission from fish on the fish namespace, so that it can’t create new tags or namespaces.

$ fish su njr
Credentials set to user njr.
$ fish perms write closed except njr fish
$ fish ls -ld fish
nr--rwcr--   fish/

Now let’s think about the permissions on the tags we have just created. There is currently nothing hierarchical about Fluidinfo’s permissions. So switching back to the fish user, we see:

$ fish su fish
Credentials set to user fish.
$ fish ls -l
trwcr--r--   fish/a
trwcr--r--   fish/b
...
trwcr--r--   fish/z

So even though njr has control of the fish namespace, the fish user has control of the tags it created. I don’t want that, so let’s transfer them over:

$ fish -U perms -f control closed except njr a b c d e f g h i j k l m n o p q r s t u v w x y z
$ fish ls -l a
trw-r-cr--   fish/a

[Again, the -U saves me having to prefixed each tag with njr/. Of course, adding globbing (wild-carding) to fish would be even more helpful; I’ll probably do that soon, though interaction with the Unix shell’s globbing will be a slight issue there.]

So this is pretty good: the fish user has read and write permissions, njr has read and control, and everyone else has read only.

The one remaining problem is that there are several different write permissions on tags—permission to tag things with the tag (in native Fluidinfo API terms, create permission on /tag-values), permission to untag objects currently tagged with the tag (delete permission on /tag-values) permission to change the description of the tag (update permission on /tags) and permission to delete the tag itself (delete permission on /tags). The last of these is the problem: I don’t really want a random user of the Shell-fish tags to be able to delete any of fish/a to fish/z. To start with, fish couldn’t recreate them (because I’ve removed write permission from fish on the fish namespace) and if it did, fish would get control permission over that tag, which is what I’ve been trying to avoid. So I need to remove the fine-grained Fluidinfo permission to annihilate the tags from fish.

In order to allow this, I added a -X option to the perms command. This “eXtra” specification restricts which particular permissions within the class specified should actually be modified. -X is followed by the fish name for a low-level Fluidinfo permission, as shown in the ls -L “longer” listing. Let’s look at the detailed permissions on one of our tags:

$ fish su njr
Credentials set to user njr.
$ fish ls -L /fish/a
fish/a:
ABSTRACT TAG (/tags)
  Write
    update (metadata):  policy: closed; exceptions = [fish]
    delete (delete):    policy: closed; exceptions = [fish]
  Control
    control (acontrol): policy: closed; exceptions = [njr]
TAG (/tag-values)
  Read
    read (read):        policy: open; exceptions = []
  Write
    create (tag):       policy: closed; exceptions = [fish]
    delete (untag):     policy: closed; exceptions = [fish]
  Control
    control (tcontrol): policy: closed; exceptions = [njr]

Here, the Fluidinfo name for the low-level permission is shown first, and then parentheses, the fish name is shown. The fish names are unique for each kind of permission that exists on tags, and the one we are concerned with is the ability to delete the tag itself—the abstract tag. This has the same name, delete, in both systems. So I used the command:

$ fish perms -f write -X delete closed except njr /fish/a
$ fish ls -L fish/a
fish/a:
ABSTRACT TAG (/tags)
  Write
    update (metadata):  policy: closed; exceptions = [fish]
    delete (delete):    policy: closed; exceptions = [njr]
  Control
    control (acontrol): policy: closed; exceptions = [njr]
TAG (/tag-values)
  Read
    read (read):        policy: open; exceptions = []
  Write
    create (tag):       policy: closed; exceptions = [fish]
    delete (untag):     policy: closed; exceptions = [fish]
  Control
    control (tcontrol): policy: closed; exceptions = [njr]

As you can see, this changed only the delete permission from the specified write class, which is what we wanted. (If I had wanted to change several, I could have repeated the -X option.) I repeated this using the other 25 tags. If we now look at the result using ls -g, we get this:

$ fish ls -g /fish
tr/-r/cr--   fish/a
tr/-r/cr--   fish/b
...
tr/-r/cr--   fish/z

Reading across:

  • The t means that this is tag
  • The r/- means that the tag’s owner, fish, has read and some write permissions on the tag—in this case, all except the delete permission on the abstract tag
  • The r/c means that there is some group of users with control and read permissions, but only some write permissions. That group is in fact the singleton [njr], and he has delete permission only. (I could have actually just made the delete policy closed—no one needs to be able to delete the tag, and I have control anyway. Equally, I could have given myself all the other write permissions; but I didn’t.)
  • The final r-- means that the world has read permission, but not write or control.

So that’s it. The fish user can now tag and untag things using the tags fish/a through fish/z but has no ability to create other tags or namespaces, or delete the tag itself, and does not have control permission. The fish user can also in principle change tag descriptions, though fish doesn’t provide a way of doing that for existing tags right now.

I have just switched over shell-fish to use the fish user for non-authenticated users, so you can try this out now. In passing, if you use ls to list the fish namespace, you’ll see this:

_static/        index.html   mkdir.html      s               unixlike.htmla               h               mkns.html       search.html     untag.html
b               help.html       n               searchindex.js  v
c               i               o               show.html       version.html
cli.html        index.html      p               su.html         w
commands.html   install.html    perms.html      t               whoami.html
count.html      j               pwd.html        tag.html        x
d               k               pwn.html        tags.html       y
e               l               q               test.html       z
f               ls.html         r               touch.html
g               m               rm.html         u

If you’re wondering what all these tags-that-look-like-web-pages are, they’re tags that I use to store the HTML fish documentation in Fluidinfo itself. If you look carefully at the documentation path — http://fluiddb.fluidinfo.com/about/fish/fish/index.html — you will see that its root is a tag on the Fluidinfo object having the about tag fish. The name of that tag is fish/index.html, and its content is the HTML for the index page. The trick lies partly in the tag name and partly in setting its content type to text/html.

I have a script that does that, which will probably become a fish command called Something like upload or publish or files2fi.

Previous topic

Like A Scrolling Terminal

Next topic

Fishier Still: rm, extra perms and more with fish 3.01

This Page