Copyright © 2004–2010 OpenSourcery, LLC. This work is licensed under a Creative Commons Attribution 3.0 United States License.
We discovered a problem while QA'ing emC against a huge client database. The page which displays who has access to a client would take a full minute to load. This was deemed unacceptable, and a solution was found.
The elementalclinic permissions system works on the idea that there are clients, personnel (staff members), roles to which personnel are members, and permissions for roles to access clients. Every staff member is given a 'primary role' that only they are a member of. Personnel become members of roles when their primary role is added as a member of a system role. This also allows for nested roles where a staff member is a member of system role a, which is a member of system role b.
Nested roles are useful when you want to share permissions between roles. For instance there is an all_clients role which grants access to all clients. The Admin role, being superuser, should also have access to all clients. With nested roles you simply make admin a member of all_clients. You can then add admins to admins, and non-admins who need all_client access to all_clients.
The problem with nested roles comes when you need to check if a staff member has permissions to view a specific client. You need to build a list of all roles the staff member is a direct or indirect member of. You then need to check if any of these roles grants access to the client. On the access page this needed to be done for each staff member.
To solve this problem I decided to leverage postgres. In the initial revision of the permissions system the database simply held the roles, direct memberships, and permissions. Traversing the roles and assessing client permissions for specific users was left entirely to the code. In the new revision I decided the database would maintain a complete map of memberships, both direct and nested. In addition the database would provide several views to simplify obtaining the results we need.
The focus of the changes is with the table that hold memberships. Initially it's schema was very simple (Old way):
21 CREATE TABLE personnel_role_member( 22 rec_id SERIAL NOT NULL PRIMARY KEY, 23 role_id INTEGER REFERENCES personnel_role( rec_id ) NOT NULL, 24 member_id INTEGER REFERENCES personnel_role( rec_id ) NOT NULL, 25 -- Make sure duplicate memberships do not occur. 26 UNIQUE( role_id, member_id ), 27 -- Roles should not be members of themselves. 28 CHECK( member_id != role_id ) 29 );
Here is the new schema for tracking role memberships:
21 CREATE TABLE role_membership(
22 rec_id INTEGER UNIQUE NOT NULL PRIMARY KEY DEFAULT nextval('role_membership_rec_id_seq'),
23 role_id INTEGER NOT NULL REFERENCES personnel_role( rec_id ) ON DELETE CASCADE,
24 member_id INTEGER NOT NULL REFERENCES personnel_role( rec_id ) ON DELETE CASCADE,
25 direct_cause INTEGER REFERENCES role_membership( rec_id ) ON DELETE CASCADE,
26 indirect_cause INTEGER REFERENCES role_membership( rec_id ) ON DELETE CASCADE,
27 -- Roles should not be members of themselves.
28 CHECK( member_id != role_id ),
29 CHECK( direct_cause != indirect_cause ),
30 -- Duplicates are pointless.
31 UNIQUE( role_id, member_id, direct_cause, indirect_cause )
32 );The main thing to note in the new schema are the 'direct_cause' and 'indirect_cause' fields. These reference other entrees in the same table. The point of this change is to track both direct and indirect memberships in one table. When a membership is added a trigger fires which adds an entree for all resulting indirect memberships.
The trigger code is fairly complicated, so I am posting a simplified psudo-code version. This trigger is fired whenever an insert occurs on the role_membership table. Note: In this psudo-code 'us' or 'we' refers to the role that is becoming a member.
Check for recursive memberships, raise an exception if found. Add memberships to all the roles the role we just became a member of is a member of. Direct cause is the new membership, indirect cause is the existing membership Add memberships to the role we just became a member of to the roles that are members of us. Direct cause is the existing membership, indirect cause is the new membership.
This trigger also fires off for any indirect memberships added by the trigger recursively. This trigger results in a table that always has a complete list of both direct and indirect memberships.
From this table it is a simple matter to create views for just direct or indirect members. Views for which roles have access to which clients is also fairly trivial. We can even create a view that shows client permissions with the reason(membership) that grants them.
Here are links to the original permissions schema, as well as the migration to the new system.
Original
Migration
And here is some additional documentation
README
Tagged as: access, elementalClinic, groups, performance, permission, permissions, postgrees, postgresql, roles, security, speed, sql, trigger, triggers
After crossing 4 states by car we arrived Thursday in Las Vegas for Defcon 17. We obtained our temporary badges, purchased some shwag, and headed off to finally get some good sleep.
Friday:
Moxie Marlinspike gave an excellent talk on defeating SSL. Using specially crafted certificate requests and flawed SSL implementations (currently most of them), one can MITM attack with no degradation in authenticity of an SSL site. Interesting and scary at the same time. Firefox 3.5 is patched with more to follow. OCSP is also a joke and easily defeated.
Next up Jason Ostrom and Arjun Sambamoorthy gave a presentation on hacking video. They have created a tool that ARP poisons RTP video streams and is able to reconstruct the streams into media files. You can also take an existing avi file and loop over an existing stream. It was interesting to see new sniffer software attacking a new type of data stream. In the attack against the Cisco phone, they had an cool hack for causing the phone to reboot and push a new config over TFTP in order to disable anti-spoofing settings.
After my video fix I hung around for Robert Clark's update on the state of Computer and Internet Law. This high ranking DHS employee had a surprisingly good sense of humor and also provided some tips for handling police, and border searches. Remember folks, if cops show up to your house to "talk", they're trying to get you to consent to a search because they don't have enough cause to get a warrant. :)
Tor was the next talk I attended. The topic was why Tor has been slow and what design changes are being considered. Tor relays wrap all individual data channels into one tcp stream. If one channel trips a tcp window adjustment, all the data channels suffer. Bit torrent was also picked on as a culprit of slowing tor. It also reminded me that I need to get some of my own tor relays up again. This talk was given by Roger Dingledine.
The last session I checked into was Dan Kaminsky's unnamed talk which ended up being on PKI and SSL. A lot of it was a rehash of the Moxie SSL presentation and how they can be exploited. It provided more back story, and a bit more detail, but the Moxie presentation was better (and first, which gets your more l33t points).
Tagged as: defcon, hacking, internet law, rtp, security, SSL, tor, video
At OpenSourcery we have a policy that all user workstations, be it laptops or desktops, must be fully encrypted.
With everything on disk under encryption, users are free to auto-login their desktop session, which allows us to continue to use one passphrase per bootup.
With this encryption in place, users are free to save passwords in browsers, login credentials for email clients, and cache svn authentication; all this information is stored in the users home directory and part of the encrypted filesystem.
One major benefit of this system is I don't have to be pushy talking to users about what data is located where, and how confidential information is used locally on a device. Users don't need to know what is cached in /tmp, that ssh passphrases can be exist in swap, or that they decrypted a gpg file locally and forgot to clean it up for a few weeks. This is on top of the obvious benefit that stolen equipment contains no useful data.
Recent versions of Ubuntu have provided an easy installation method for using LUKS (Linux Unified Key Setup). The catch is you need to download and use the Alt install CD. Select "Use LVM and encryption", provide your passphrase twice, and everything on disk will be encrypted (minus a small /boot partition where no sensitive data is stored and is used to get the kernel going to support LUKS).
A couple months ago I manually formatted an external USB drive with LUKS. This was to make a backup of my entire laptop prior to going on vacation (yes.. I really need to ditch the laptop during vacations). After the rsync I put the drive under my desk and forgot about it.
All our important data is stored in svn repositories, so it's rare that I need to make a full backup of my laptop. Kicking the drive a couple times by accident reminded me I was due for another full backup.
Upon connecting the USB cable I was presented with a Gnome window detecting the LUKS configuration and asking for my passphrase. This was unexpected, and though I'm quite capable of hacking crypttab and using cryptsetup, plug-n-play disk encryption is quick and easy (this was under Ubuntu 8.04).

Ubuntu 8.10 brings a new encryption feature during the Alt install (which I use 99% of the time over the standard desktop installer). Encfs is a new option during install that asks if you want your home directory to be encrypted. Instead of LUKS block level encryption, EncFS is an abstraction layer for per-file based encryption with views to hide the encrypted files. I will need to do some research on this method before I recommend its use, but it's good to see Ubuntu trying to incorporate security with user-friendliness.
With data becoming more important, and computing devices becoming smaller, no device should be running in unsecured environments without storage encryption.
Tagged as: encryption, luks, security
A common scenario we encounter is where the bulk of a site's traffic is anonymous users, for whom it would be an unnecessary burden on the server to transfer pages with SSL. However, it is still desirable to serve some parts of the site with SSL (typically the admin pages, or perhaps some commerce-related pages). Luckily, the securepages module accomplishes this nicely.
This approach has a drawback, however. The same session cookie is used to access both SSL and non-SSL pages. Since this cookie is passed around in plaintext, it's easily hijacked by an attacker, who can then access your SSL-protected pages with the hijacked session.
Tagged as: Drupal, securepages, security, SSL