If you've got a laptop computer, it's not a bad idea to encrypt a data partition and keep all your personal data there. That way if your laptop gets lost or stolen, then the thief may have your computer, but they won't be able to steal your identity, too. And, doing so in linux is absurdly easy. Here's how I did it on Ubuntu. Also note that, if you've been here before and already have the encrypted partition, but are trying to access it from a new install of Ubuntu, you should *skip* steps 2, 4 & 6

Step 1) Use Synaptic to install the 'cryptsetup' and 'pam-mount' packages.

Step 2) Create a new primary partition that will be your encrypted partition (I recommend using gparted to do this).

Step 3) Restart your computer. This is a step I frequently forget, but is absolutely necessary for the right encryption modules to be loaded into your kernel.

Step 4) Run 'sudo cryptsetup luksFormat /dev/sdXX' where 'sdXX' is the name of the new partition you created in step 2 (eg, sda4). When asked for a passphrase, use the exact same password you use to login to the computer (you'll see why in step 9). Notice and heed the warning "This will overwrite data on /dev/sdXX irrevocably."

Step 5) Run 'sudo cryptsetup luksOpen /dev/sdXX sdXX'

Step 6) Run 'sudo mkfs.ext3 /dev/mapper/sdXX'

Step 7) Create a folder to mount your partition to. I like to use /mnt/sdXX, but you could just as easily put it right in your home directory, such as '~/encrypted'. Note the all instructions below assume you chose '/mnt/sdXX', so adjust accordingly.

Step 8) Run 'sudo mount /dev/mapper/sdXX /mnt/sdXX'

Ok, now your partition is created and mounted. But, next time (and every time) you restart your computer you'll need to run step 8 again. If you forget, you'll find that /mnt/sdXX is empty, and panic. Wouldn't it be nice if you could just mount that partition automatically whenever you log in? Well, as long as you used the same passphrase for the for the partition as your password when you log in, you can.

Step 9) As root, open /etc/security/pam_mount.conf.xml and add or uncomment the line that says '<luserconf name=".pam_mount.conf.xml" />'

Step 10) Create a file named .pam_mount.conf.xml in your home directory and fill it with the following...

<?xml version="1.0" encoding="utf-8" ?>

<pam_mount>

<volume fstype="crypt" path="/dev/sdXX" mountpoint="/mnt/sdXX" />

</pam_mount>

Step 11) As root, edit /etc/pam.d/gdm and add '@include common-pammount' to the end of the list.

Step 12) Reboot and you should find that the encrypted partition gets mounted for you.

One final word of warning. If an UNencrypted partition fails or gets corrupted, there are still some very crude methods to *try* and recover anything that wasn't properly backed up. When an ENcrypted partition fails like this, you can probably throw most or all of those tools and techniques out the window. So, keep your encrypted partition frequently backed up to a different *physical* drive, probably external, probably also encrypted.

Comments: 0 [add comment]
  • ICandy

At my day job we have several Rails apps that we've built and continue to maintain and enhance. We often add features that are usable in all of our applications, so although they're often initially developed in one app or another, they quickly get turned into plugins that we can share across all of our apps.

My boss and fellow Rails developer Aaron Baldwin has been typically hacking on plugins that are strictly internal and wouldn't be of much use to anyone outside of our organization, whereas I've been fortunate enough to get to work on things that are more generic and thus releaseable to the broader community. So, it's particularly noteworthy that Aaron released his first public Rails plugin this week, and this is one of those plugins that, now that I've used it, I don't know how I could have ever coded Rails without it.

Here's what it's for. When writing integration tests you often test that certain elements exist on the page. The problem though, is that when one of these tests fail, all you're told is that an element of some type was expected, but none were found. Was the element really not there? Or is there a typo in your test? Or on the page? Or... what? I've found myself in this scenario desperately wishing I could just see the page that the test was testing in my browser window so I could look for myself.

Enter ICandy. ICandy is a Ruby on Rails plugin that automatically displays the page from failing integration tests in your browser window. You can also manually trigger certain pages to open in your browser, if you desire. It's been tested to work with Safari and Firefox on Mac and Firefox on Ubuntu.

Comments: 0 [add comment]

I recently added attachment_fu to a personal Rails project that was already using GateKeeper and ran into some stumbling blocks. It took me some time to dig into attachment_fu's inner workings and some experimentation to figure out the best way to get to the two plugins to play nice together, so here's some tips for anyone else who might try this themselves someday.

attachment_fu is a Ruby on Rails plugin by Rick Olson that facilitates file uploads and is the successor to Rick's acts_as_attachment plugin. GateKeeper is a Ruby on Rals plugin by yours truly that provides a natural language DSL to easily setup and manage highly complex RBAC permission rules at the model level.

I'm going to use 'Picture' as my attachment_fu model for these examples. Typically with attachment_fu, this model would probably look something like...

class Picture < ActiveRecord::Base
  belongs_to :user
  has_attachment :content_type => :image, :max_size => 50.kilobytes, :thumbnails => {:thumb => 'x42'}
end 

Now, with gatekeeper, you might expect to just add a couple simple permissions so the owner can create, update and destroy the picture and share it with other users, such as....

class Picture < ActiveRecord::Base
  belongs_to :user
  has_attachment :content_type => :image, :max_size => 50.kilobytes, :thumbnails => {:thumb => 'x42'}
  
  ## Permissions ##
  crudable_by_my_user
  readable_by_anyone
  #################
  
end 

Note that the readable_by_anyone permission assumes that you have a 'is_anyone?' User instance method that always returns true.

There are two problems with the above. First, you're going to have issues the first time you try to access the thumbnail version of the image. Second is that the above is using the default :db_file storage method which actually adds a another ActiveRecord model, and which GateKeeper will immediately lock down tight. If you're not using thumbnails or the :db_file storage method, then the above is probably all you need. Everybody else, keep reading.

First, let's address the thumbnail issue, since that's the easiest to deal with. In order to support thumbnails, attachment_fu's instructions tell you to add a 'parent_id' column to your 'pictures' table. attachment_fu then automatically provides a 'parent' association on thumbnails that point back to the original uploaded image. You're going to want thumbnails to just inherit their GateKeeper permissions from the original image, so that anyone with permission to read or delete the original image can do the same to the thumbnails. To do this, just add a 'crudable_as_my_parent' permission to Picture. (Notice that that says as_my_parent, not by_my_parent.) This will allow anyone who can read the original to also read the thumbnail, and anyone who can destroy the original to also destroy the thumbnail.

class Picture < ActiveRecord::Base
  belongs_to :user
  has_attachment :content_type => :image, :max_size => 50.kilobytes, :thumbnails => {:thumb => 'x42'}

  ## Permissions ##
  crudable_by_my_user
  readable_by_anyone
  crudable_as_my_parent
  #################
end 

Ok, that was actually pretty easy. The :db_file storage method is just a little more challenging. If you're using :filesystem or :s3 as your storage medium for uploaded files, then you should be fine since neither of these use extra ActiveRecord models to access the files, so GateKeeper won't get in the way. However, if you're using :db_file, here's what you want to do. First, create a db_file.rb file in /app/models and make it look something like this (changing all three (3) occurances of 'picture' to match whatever your attachment_fu model is).

class DbFile < ActiveRecord::Base
  has_one :picture
  crudable_as_my_picture
  crudable_by_anyone :if => lambda {|db_file| db_file.picture.nil? } #pic already destroyed
end

The first line provides an association for GateKeeper to use to get back to the picture model. The second line tells DbFile to inherit it's GateKeeper permissions from the picture provided by the association. The third line is the tricky one. When pictures are destroyed, Rails will destroy the picture first, then automatically try to destroy the associated db_file (via a ':dependent => :destroy' call). However, when it goes to delete the db_file, there won't be a picture anymore to inherit permissions from, and line two will fail. We can safely assume though that if a db_file is being destroyed and if (and only if) the picture doesn't exist, it too must have just been destroyed by the current user and the db_file should follow suit. You should never have stray :db_file objects left in your database whose associated objects are gone, so there's really no risk in allowing anyone to destroy one in such an orphaned state.

We're almost done, but not quite yet. The last problem is that the DbFile class you just defined will never get loaded by Rails. attachment_fu is going to create it's own DbFile and the permissions you setup will never get loaded or used. So, let's go back to the Picture class and add one line to the very top to force your DbFile class to load before attachment_fu tries to create it's own.

require_dependency 'db_file'
class Picture < ActiveRecord::Base
  belongs_to :user
  has_attachment :content_type => :image, :max_size => 50.kilobytes, :thumbnails => {:thumb => 'x42'}

  ## Permissions ##
  crudable_by_my_user
  readable_by_anyone
  crudable_as_my_parent
  #################
end 

And that's it. GateKeeper and attachment_fu should play nice together now, giving you file upload wonderfulness and model security peace of mind. One last thing I'd like to briefly touch on is the possibility of having more than one attachment_fu model. Let's say you're running a job site that allows users to upload a photo of themselves AND a pdf resume. So, you're going to have both a Picture and a Resume class, and DbFile is going to need associations to both. Note that I haven't actually tried this, but updating your DbFile class that you built above to the following should work just fine. (Continue the pattern for any additional attachment_fu models you want to add to your application.)

class DbFile < ActiveRecord::Base
  has_one :picture
  has_one :resume
  crudable_as_my_picture
  crudable_as_my_resume
  crudable_by_anyone :if => lambda {|db_file| db_file.picture.nil? and db_file.resume.nil? }
end
Comments: 0 [add comment]

I just got back from the first Misoula BarCamp, and I think it was a success. We had about 18 people show up, which I think is very good for the first one. One attendee ( a fellow Rails developer ) came all the way from Helena. There were also some people that I was hoping/expecting would be there that weren't so hopefully they'll come to the next, whenever that is. There was a great mix of technical and non-technical discussions and presentations (I gave a little Rails demo). At any rate, big shout out and thanks to Harold for putting the whole thing together. I don't think anybody who went was the least bit disappointed in doing so, despite missing out on the first really nice spring weather in a couple weeks.

Free Image Hosting by FreeImageHosting.net
A few of the attendees looking over the topics board to
pick out which sessions they're going to go to.
Comments: 2

I've noticed in my site logs people are searching the Interweb Tubes for "GateKeeper" combined with other keywords that suggest they're looking for some better examples on how to use it, so I figured maybe I'd write something up to try to help.

GateKeeper is a Ruby on Rails plugin providing a natural language DSL to manage security permissions on instances of ActiveRecord classes at the Model level. Permissions may be assigned based on the current users roles, and/or by their relationships to the object in question. GateKeeper automatically intercepts all attempts to CRUD (Create, Read, Update & Destroy) instances of ActiveRecord classes and verifies the current user has permission before allowing the operation to proceed.

The main requirement of GateKeeper is that it expects that you have a 'User' class, and that it responds to the class method 'current', as in 'User.current'. If you need to use a different class (such as 'Person' or something), that can be defined in your environment.rb, but whatever it's called, it must respond to 'current' and return an object that represents the currently logged in user. So, here's a simple example of how to set that up.

Exactly how you get your users logged in is up to you and still beyond the scope of this post, but I'd recommend a SessionsController and a User.login(username, password) method. So, we'll assume that you have that setup already and that you store the 'id' of the currently logged in user in session, such as 'session[:user_id]'.

The first thing you'll want to do is have a method in your application controller that sets up the current user for the rest of the application...

class ApplicationController < ActionController::Base
  before_filter :setup_user

  def setup_user
    User.current = User.find(session[:user_id])
  end
end

Now, we need to add 'current' and 'current=' methods to User.

class User < ActiveRecord::Base
  
  ## Class Methods ##
  class << self
    
    def current
      @CURRENT_USER || User.new(:username => 'guest')
    end

    def current=(u)
      @CURRENT_USER = u
    end

  end

end

And that's it for User.current. Now, anywhere in your application (Models, Controllers, Helpers, and Views), you can just call User.current, and get an object that represents the currently logged in user. Now we'll go into some basic uses of GateKeeper.

If users can register new accounts on your site, then you'll need to allow 'guest' users permission to create new users. Update your User class with the following (previously shown class methods left out for brevity).

class User < ActiveRecord::Base
  ## Permissions ##
  creatable_by_guest
  #################

  def is_guest?
    username == 'guest'
  end
end

However, if at any point your application tries to save the current user, it could potentially end up creating a user with the username 'guest', which you probably don't want. So, update the above with the following...

  ## Permissions ##
  creatable_by_guest :unless => lambda {|new_user| new_user.is_guest? }
  #################

The 'is_guest?' method above is an example of how to define dynamic 'user roles' for GateKeeper. When you say 'creatable_by_guest', GateKeeper expects to either find a 'is_guest?' instance method on User, or a Role named 'guest' belonging to User.current (see below). Here are some examples of other dynamic user roles that you might want to define for your users.

class User < ActiveRecord::Base
  def is_premium_member?
    premium_membership_expires_on > Time.now
  end
  
  def is_logged_in_user?
    !is_guest?
  end

  def is_popular_user?
    popularity_ratings.size > 42
  end
end

class Foo < ActiveRecord::Base
  ## Permissions ##
  creatable_by_premium_member
  updatable_by_popular_user
  readable_by_logged_in_user
  #################
end

As I stated above, GateKeeper also looks for a Role belonging to User.current with the name of the Role used in the permission. To set this up, you'll want the following...

class CreateRoles < ActiveRecord::Migration
  def self.up
    create_table :roles do |t|
      t.string :name
      t.timestamps
    end
    add_index :roles, :name
    
    create_table :roles_users, :id => false do |t|
      t.integer :user_id
      t.integer :role_id
    end
    add_index :roles_users, :user_id
  end

  def self.down
    drop_table :roles
    drop_table :roles_users
  end
end

class User < ActiveRecord::Base
  has_and_belongs_to_many :roles
end

class Role < ActiveRecord::Base
  has_and_belongs_to_many :users
end

Now, if you were to create a role named 'moderator', and assign it to a few of your users, you could give those users special permissions on certain models, such as updatable_by_moderator . Take note that the role name should be all lower case and underscored so that your permissions look nice. If you have a role named 'SpecialUser', then your permissions would need look like 'readable_by_SpecialUser' which isn't beautiful code, and if the role name has spaces in it, it won't work with GateKeeper at all. 'special_user' is a much more appropriate role name for GateKeeper's purposes.

So, there you have it. I hope that helps some people get over the initial hurdle of setting up GateKeeper. I'd love to hear from anyone using GateKeeper and hear your thoughts and questions.

Comments: 0 [add comment]

I've just released ARID 0.5. This is a minor update with some small bug fixes and optimizations.

ARID ( ActiveResourceIntegrationDsl ) is a Ruby on Rails plugin offering easy to use methods for writing integration tests on RESTful Rails apps. With ARID you write simple statements like user.builds_article(:params => {:article => {:subject => 'Hey!', :content => 'Hello World!'}}) which will GET your new_article_path, check that it has a properly formatted form with fields for all the given params, and then will POST the params to articles_path and assert the expected response. You can even pass a block to the above call to perform additional tests. And YES, ARID tests AJAX calls.

More info and installation instructions at http://arid.rubyforge.org.

Comments: 0 [add comment]

I've just release version 0.3.1 of Cross Site Sniper. This is a minor bug fix update.

Cross Site Sniper is a Ruby on Rails plugin that automatically html escapes all string and text fields of ActiveRecord objects. Data is escaped as it is retrieved from the database to protect your site from XSS (cross site scripting) attacks without modifying or corrupting your original data. Convenience methods are provided to access the unescaped data when necessary. Edit forms are prepopulated with unescaped data as well to avoid user confusion and prevent double escaping.

Documentation and install instructions can be found at http://xss.rubyforge.org.

Comments: 0 [add comment]

Obama and BarCamp are coming to Missoula. Thankfully, not on the same day.

Thanks to my new Missoulian RSS Feed (what? huh? move along, nothing to see here... next post on that subject) I just found out that Presidential Candidate Barack Obama is having a free rally at the Adams Center Saturday morning. I'd be there even if it was Bush III, I mean John McCain. This is history in the making folks!

And on a completely unrelated note, Missoula is having it's own BarCamp on April 26th (also a Saturday). What's a BarCamp? According to Wikipedia....

BarCamp is an international network of user generated conferences — open, participatory workshop-events, whose content is provided by participants — often focusing on early-stage web applications, and related open source technologies, social protocols, and open data formats.

The official site for Missoula's contribution is at http://missoulabarcamp.org. Registration is required. Early registration recommended. I hope to see a great turnout of Missoula's Tech Professionals.

Comments: 0 [add comment]

GateKeeper 0.2 is now available. This version traverses eagerly loaded associations and checks read permissions on each loaded object for the current user. Rdocs and install instructions available at gatekeeper.rubyforge.org.

GateKeeper is a Ruby on Rails plugin providing robust Model level permissions management, allowing you to declare access permissions for instances of ActiveRecord classes with natural language commands. For instance

  • crudable_by_admin
  • creatable_by_my_author
  • updatable_by_friends_of_my_owner :unless => :is_imaginary?
  • updatable_by_monkey_of_my_uncle :if => :has_common_ancestor?
  • readable_by_employee_of_the_month
  • and a whole lot more.
Comments: 0 [add comment]

Well, it was a little more work than I'd originally anticipated, but 5Valleys is now both my personal OpenID server and a consumer for visitors wishing to use OpenID to identify themselves when posting comments. I used the ruby-openid gem, but otherwise wrote all my own code, trying to stay as RESTful as possible (OpenID itself isn't particularly friendly to REST practices), and getting a thorough understanding of the internals before my presentation at next week's Missoula Web Discussion Group meeting. If you have an OpenID, go ahead and post a comment to try it out. Hint: if you have accounts at any of these sites, then you've got an OpenID you can (hopefully) use here, or anyplace else that proudly accepts them.

Comments: 0 [add comment]