On Authorization Failures

As a slight extension to the previous post, I wanted to make a quick point about authorization failures.

Given you’ve raised SomeAuthorizationFailure exception in a controller action, you might have a general rescue handling it:

rescue_from 'SomeAuthorizationFailure' do
  render :text => "Bad user!", :status => 403
end

The key here is the 403 status, Forbidden. This is a pretty natural, and technically correct status to feed the client.

Cool, let’s wrap that up, it’s done! Hold on, not so fast.

If you use Github (if?), you may have noticed something that struck you as curious the first time it happened. Say you’re hanging in the dev campfire room, and somebody pastes a link to a line of code for you to checkout (like /foocorp/awesomeproject/config/application.rb#L7). You clicked on the link but forgot you’ve logged out. Boom….403 Forbidden.

Wait..no that’s not a 403, it’s a 404. What the heck?

The answer is pretty simple. On your little todo app you run for friends and family, it’s probably not a huge deal for somebody to hit /todo_lists/42/item/5 and get a 403. Wow, somebody now knows you have a todo list 42 and item 5. Probably not a big deal.

But on a site like Github, let’s change that application.rb link to say, /foocorp/awesomeproject/config/initializers/devise.rb. 403? Oh look, that project is using Devise!

The moral of the story: best to give a 404 status on authorization failures if you don’t want to cater to mining and leaking of sensitive info.

Apr 24, 2013

/2013/04/24/on-authorization-failures.html comments

On Authorization Patterns

Once upon a time, I’d heavily lean upon scoped finds for cheap authorization in Rails controller actions. For instance, a system might have many users, for which each has many projects they can manage. In order to find a project that a user can administer, an action may include the following:

@project = current_user.projects.find(params[:id])

This can work. If a user tries to hit project id 42, for which they aren’t associated with, the execution short circuits at that point. The security on that project has been maintained.

I think most people know at this point, this is a poor general authorization scheme, because for one, it spreads your authorization logic, no matter how simple, around the application. With a few controllers in a small system, this probably isn’t a big deal.

Enter an authorization scheme, you might write:

@project = current_user.projects.find(params[:id])
authorize @project

The authorize method here will typically take the current user, lookup some policy object, and run a check. If a user can be associated to a project, but not be able to edit it, this will probably pan out as you expect.

Sometimes though, you could simply write such code to be:

@project = Project.find(params[:id])
authorize @project

This can be a subtle, but I believe powerful, difference. First, your finder usage is simplified. But second, and I believe more importantly, the code becomes more straightforward and your exceptions more accurate. Take another look:

# If no project is found, raise ActiveRecord::RecordNotFound
@project = Project.find(params[:id])
# If the user is not authorized, raise SomeAuthorizationException
authorize @project

This is a worthwhile difference. Want to keep metrics or get alerted on security violation attempts? Now it can be clearly split. Or perhaps, you take different action or set different flash messages; this can be handled more cleanly now.

When it comes to patterns, remember, it’s never one-size-fits-all. What’s good to realize is that sometimes you can write your code in simpler fashions, and more importantly, think about the explicit exceptions your system should be throwing, if any.

Apr 23, 2013

/2013/04/23/on-authorization-patterns.html comments

A note about "friendly" passwords

Often in a web application, the time will come where you opt to generate temporary passwords for users. One common approach to this is to use a helper that combines a small about of random data (such as 4 random numbers) with a word randomly selected from a pared down dictionary list.

Please don’t do this. There are at least two reasons:

If the day comes and the system generates the password “cigar1984” for somebody trying to quit smoking, that could be awkward.

Now, I’m no crypto expert, but I’m going to assume that the ruby SecureRandom library will do a better job than me at outputting random strings. So it’s of use here. For example:

require "securerandom"

# outputs something like "Ht25IeNqIBUp"
SecureRandom.urlsafe_base64.gsub(/[^a-z0-9]+/i, '')[0,12]

This strips non-alphanumeric characters such as ‘_’ and ‘-’ out. This is useful because people are less used to typing them, and also, certain mouseclick-to-copy behaviors will split on those characters depending on the environment.

It’s worth noting that certain characters often will confuse users if they are manually entering a password as viewed from the screen. Fonts can make characters including the following difficult to distinguish

You can String#tr these out for substitutions, or strip them alltogether. This will slightly reduce entropy, but by keeping a longer password you compensate somewhat.

Jan 26, 2013

/2013/01/26/a-note-about--friendly--passwords.html comments

An Example of Wrapping

You’ve been tasked with adding comments to some internal system at work. You throw together some new controllers and views into your app, and churn out the feature quickly and efficiently.

A few days pass, and a peer comes and informs you, “Hey, have you seen the comments? Some people are swearing up a storm and Bob is irritated!” You are left wondering, what to do. You quickly discover there’s an Obscenity gem for Ruby, and get cracking. At stage one, you’re just going to output sanitized versions of comments, rather than resort to draconian measures.

Let’s assume an overly simple, Comment model with one property, content, that looks like this:

Comment = Struct.new(:content) do
  #...
end

Dont’ worry about database, etc, it’s beyond the point right now. Dropping in a #clean_content method is quick:

Comment = Struct.new(:content) do
  def clean_content
    content && Obscenity.sanitize(content.dup)
  end
end

Now off to update the views and change the references to @comment.content to @comment.clean_content and you’re done. Wait, not so fast, that’s only one option, with others to consider. Possible options include:

Here’s a quick example of accomplishing the last. The presenter/exhibit/delegate pattern in Ruby are often presented as a way to decorate new methods onto an instance, such as taking an underlying object with an #amount_in_cents attribute and adding a new method for outputing it as readable currency. Another way to leverage this is to intercept calls to an existing method, like #content, and change its behavior. Let me show you what I mean.

First, SimpleDelegator can provide an easy wrapping for instances:

class CleanComment < SimpleDelegator
  # In case you want to get back at the original
  def unsanitized_content
    __getobj__.content
  end

  # Ensure clean content
  def content
    clean_content
  end
end

When you want to sanitize the comment, say after finding it via a controller, wrap it:

@comment = CleanComment.new(comment)

Now your views can keep rolling on with a calls to @comment.content and be none the wiser. Remember, Ruby’s duck typing is powerful; rely on what instances respond to, as opposed to what they are instances of.

This is partially a matter of taste, remember there’s often not a “right way”. What’s important is to have options, and leverage the option that feels right given the situation at hand. Different approaches have different pros & cons. With wrapping, for instance, you have to remember to wrap! And if it’s a collection, you must wrap them all. There’s gems like draper or display-case that can help you on your way.

Jan 15, 2013

/2013/01/15/a-simple-example-of-wrapping.html comments

Two Support Objects You May Have Missed

If you spend time daily in a large ruby project (such as a Rails app) that has ActiveSupport pulled in, you are likely relying on its string, time, hash, and other extensions. I’ve found two objects it provides prove useful, and having found them lesser known amongst my coding friends, figured they are worth sharing.

The first useful tidbit is the ActiveSupport::StringInquirer class. It’s a simple method missing call that lets you do prettier equality tests on strings. If you’ve ever done a Rails.env.development? check, it uses this implementation. Let’s go to the code:

Rails.env.development? # => true
Rails.env              # => "development"
Rails.env.class        # => ActiveSupport::StringInquirer

si = ActiveSupport::StringInquirer.new("foo")
si.foo? # => true
si.bar? # => false

I think this is great for two reasons. First, it’s a more expressive use of code, and secondly, it implies less coupling to a string outside of an object. Let’s take a simple example: a role for a User object. Imagine you start simple, where role is just a string. Now let’s say we’re using CanCan to add simple authorization to our app, with an ability class that looks like this:

class Ability
  include CanCan::Ability

  def initialize(user)
    user = user || User.new

    if user.role == "admin"
      can :manage, :all
    else
      can :read, :all
    end
  end
end

Note we’re doing an #== for comparison on that role. This is a bit ugly and not as expressive as I’d like. Let’s get rid of ugly with the help of the StringInquirer.

class User < ActiveRecord::Base
  def role
    role = read_attribute(:role).to_s
    ActiveSupport::StringInquirer.new(role)
  end
end

class Ability
  include CanCan::Ability

  def initialize(user)
    @user = user || User.new

    if role.admin?
      can :manage, :all
    else
      can :read, :all
    end
  end

  private

  def role
    @user.role
  end
end

I’ve redefined User#role to wrap the attribute in a StringInquirer, and updated the Ability class to call the role with the predicate #admin? method. Our end behavior for ability checking is the same, but I think we’ve got more readable code. There’s another win on this: we’ve decoupled from treating our role like a string which can pay out nicely in the future. Imagine for instance the day arrives when a user no longer has one role, but many. A simple user may be able to function as both a forum moderator or a comment moderator. You can shift to supporting many roles per user with a bitmask method and leave your external calls untouched. A simple application of define_method or method_missing on your role attribute wrapper is all you need to keep rolling. Now, you could also define #== on your role object for such string comparisons, but comparing to a string reads more like the caller knows too much of an implementation detail. I haven’t touched on the User#role= setter here; you may need some sanitizing and cleanup on it if you were assigning it the results from the getter method anywhere (and, ahem, possibly breaking encapsulation with your own string assignments, too). I’ll leave that as an exercise for the reader.

Our second friend is the ActiveSupport::SecureRandom interface. Actually, saying this is from ActiveSupport is a little misleading. If you are working on an older Rails 2 project, you’ll probably be using this by way of ActiveSupport. However for modern and future use, this is deprecated and delegated to Ruby 1.9.x stdlib’s SecureRandom. SecureRandom is great for generating random character strings on the fly that are useful as API keys, temporary passwords, tokens, etc. It’s simple to use, and can replace those naive calls to rand() you’ve been making for generating random strings. Don’t reinvent the wheel! I’ll leave you with a few examples:

SecureRandom.hex    # => ace59c788b498fadcaa88216e45cf800
SecureRandom.base64 # => iJKR2NQ8Jk1wBdp0nU/fhA==

# Optionally pass 5 for 5 hex pairs
SecureRandom.hex(5) # => a5f8bf212f

Oct 16, 2011

/2011/10/16/two-support-objects-you-may-have-missed.html comments