Tag Archive for 'ruby'

Killfile 2.0

There’s been an persistent blog-wank-fest making the rounds over the last few weeks about the state of the Ruby community: whether it’s become more or less “fun”, “creative”, etc. I’m not going to reward any of the participants with a link, but I do offer the following balm if you, like me, are a bit sick of hearing about it:

%w(open-uri rss resolv uri rubygems hpricot).each {|lib| require lib }

blog_url = ARGV.shift

blog_hdoc = Hpricot.parse(open(blog_url))
rss_links = blog_hdoc / :head / 'link[@type="application/rss+xml"]'

feed_rss = RSS::Parser.parse(rss_links.first['href'])

rants = feed_rss.items.select {|i| t = i.title; t =~ /rant/i && t =~ /ruby/i }

if rants.empty?
  puts "Okay, you get a pass."
else
  puts "Bad blogger! No biscuit!"
  hostname = URI.parse(blog_url).host
  ip_addr = Resolv.getaddress(hostname)
  `sudo route add -host #{hostname} gw 127.0.0.1`
end

Granting just enough power, but no more

Sometimes you have a group of users who need to run certain commands on a server, and no others. It’s not necessarily that you don’t trust them. The point is simply that they don’t need a full-blown shell account, and you’re understandably reluctant to give it to them.

There are countless ways to set up a restricted account that can use only certain commands, but most of them are either extremely special-purpose, or rather difficult to set up. (Locking down SSH sessions inside a chroot jail, for example, requires almost as work as just setting up a dedicated virtual machine for your untrusted users.)

Furthermore, none of the existing solutions were written by me, to address exactly the needs I have for such a “sandbox” environment. Most notably, I don’t want users to even have to remember which commands are available to them. In many cases, they may only be using these tools every few months, and remembering cryptic UNIX-y command paths and syntax is hard enough even when you use something every day.

And so, I give you menush, a simple shell replacement which presents users with a list of available commands from which the user may choose. It loops until the user exits via the menu (or uses Ctrl-C/Ctrl-D to end the session).

To set it up on your own server, you’ll need to copy the file into a known location (say, /usr/local/sbin), then add a line to your /etc/shells file pointing to it. For each user you want to lock into a sandbox, edit their password entry using vipw (or your passwd editing method of choice) and change the last field from /bin/bash or similar to the full path to menush.

Then, create the directory /etc/menush, and write your default menu file (/etc/menush/__default__). On startup, menush will look in that directory for a file with the same name as the user being logged in; if that file is absent, the default will be loaded instead. The format for the menu files is documented in the README, but it’s just a YAML file. (Also, bonus points for the first person to correctly identify the gaping security hole in the provided example.)

The code is written in a fairly portable, POSIX-y style, so it should work on Linux, BSD, or OS X. Feel free to send me suggestions, pull requests, or rants about the horrible security holes I left because I banged this whole thing out in like two hours and then spent a bunch of time blogging about it instead of reviewing my own code.

New toy: misfict

Being home alone with a head cold doesn’t leave one with a lot of excuses not to knock off a quick project. I had been mulling over the idea of building a version of the classic “storytime” party game as a webapp for a long time, and since I also wanted to spend a little more time working with jQuery’s AJAX and JSON support, it seemed reasonable to tackle both at the same time.

So, without further ado, I present misfict, the micro-serial-fiction engine. The process is simple: read the last line someone else wrote, then post your own idea for the next sentence in the story. Eventually, we should end up with a lovely stream-of-consciousness story co-authored by anyone who cares to drop a few words into the bucket.

I may build in some sort of cap for the number of sentences before a story is finished, or periodically declare a “chapter break”, but for the time being, the story will keep going as long as anyone is writing.

PS. any perceived relation between the release of this project and the upcoming start of NaNoWriMo is strictly a coincidence.

PPS. If you’re interested, all the code is available on GitHub

PPPS. (last one, I promise) I got the misfict.com domain, so the link above has been corrected to point there. Also, there’s an RSS feed. Now, go write something.

Mixins without monkeypatching

Anyone who’s done much Ruby metaprogramming (or even just skimmed the source code to Rails) should be intimately familiar with the following idiom:

klass = Foo::Bar
# ...
klass.extend(Some::Module)

This is a programmatic mixin — it adds the methods defined in Some::Module to the class Foo::Bar for the duration of the current Ruby process. It also does so for all instances of Foo::Bar, whether defined in some scope known to the caller of extend or not.

If may not look like it, but this is yet another case of monkeypatching. The only reason you don’t see it being denounced up and down the ‘tubes like, say, overriding method_missing on NilClass is that it’s usually confined to an application or framework-specific class, like ActiveRecord::Base.

Now, I’m all for the judicious use of powerful language constructs like open classes, but they can be a problem for large-scale projects, or those where collaboration between team members is less-than-perfect. The global and persistent scope of a class-level #extend call like the above can cause unexpected side-effects, too.

As an alternative, I humbly propose the use of instance-scoped extensions. In cases where not all instances of a class may need the additional functionality provided by the mixin, try calling #extend on just that instance. It keeps your namespace clean, doesn’t introduce as many potential pitfalls for code in other scopes, and is reversible: just nil your current reference to the object, and re-create it without the mixin.

Here’s an example, cribbed from some refactoring I’m doing of a web service implementation:

def change_password
  token = AuthToken.find(params[:token])
  active_user = Account.find(token.identity)
  password = params[:password]

  raise ArgumentError, "passwords did not match" unless password = params[:confirm_password]

  if token.has_privilege?(:password_reset)
    active_user.extend(PrincipalManagement)
    active_user.change_password(password)
  end

  render :x ml => Account.to_xml
end

One reason this is expecially handy for me is that I can re-use the same model core model classes (like Account) in different applications, only some of which may have the privileges necessary to change passwords, delete accounts, etc.

By limiting the mixin to a single model instance within the scope of a single request, I also protect myself from coding errors that might expose dangerous mutators to untrusted callers. Any attempt to call change_password (or a similarly-restricted method) from outside a scope which explicitly included the mixin will raise a MethodNotFound error, without any additional access-control checks on my part.

Happy thoughts

I find it hard to be optimistic on Mondays. Sometimes, I just need a reminder that everything is going to be okay.

So, I put the following code snippet at the end of my ~/.bashrc file:

ruby -rdate -e'puts "#{Date.new(2009, 1, 20) - Date.today} days left until Bush leaves office."'

Now I smile every time I open a terminal on my work machine.

Update: Ten minutes of late-afternoon golfing later, I’m left with this little beauty:

ruby -e'T=Time;puts "%s days, %s minutes, %s hours, and %s seconds left."%[86400,3600,60].inject([(T.local(2009,1,20)-T.now).to_i]){|a,v|p=a.pop;a+=[p/v,p%v]}'

Dispatch from Toronto

So far, this has been easily the best conference I’ve attended since LL1. Serious nerd-ery, great hallway-track conversations, and a single track of talks limited to 30 minutes have made for a very desirable signal-to-noise ratio.

Nick Sieger’s talk on jazz and programming was the highlight of today’s talks, at least for me, but the overall level of presentation was pretty damn good.

The continuing flow of excellent food + free drinks hasn’t dampened anyone’s spirits as far as I can tell, either.

That being said, I am more than a little disappointed that I’ll be missing FOSCON. For those who haven’t had the pleasure, and have any chance of being in the Portland area next Wednesday night, I can’t recommend it highly enough. In my experience, it manages to pack about 50% of the awesomeness of a two-day conference like RubyFringe into a mere three hours, and does so with a singularly “Portland DIY” attitude.

Perhaps there’s an opportunity to bring the two events closer together next year?

IMAP ‘append’ example

# imap-append-example.rb
# requires TMail library (http://i.loveruby.net/en/prog/tmail.html)

require 'net/imap'
require 'tmail'

IMAP_HOST = 'imap.example.com'
IMAP_USER = 'user'
IMAP_PASSWORD = 'password'
IMAP_MAILBOX = 'INBOX.scratch'

# Connect and authenticate
imap = Net::IMAP.new(IMAP_HOST)
imap.login(IMAP_USER, IMAP_PASSWORD)

# Create the target folder if needed
imap.create(IMAP_MAILBOX) unless imap.list(IMAP_MAILBOX, "*")

# Insure the message timestamp will be consistent
created = Time.now

# Create our email object
msg = TMail::Mail.new
msg.from = 'ruby@example.com'
msg.to = 'me@example.com'
msg.date = created
msg.subject = 'Inserted by Ruby'

# Finally, append the message to the mailbox. The line ending
# argument is needed to make sure the TMail::Mail#to_s method
# doesn't generate invalid, "\n"-terminated lines
# Also, you can remove the :Seen symbol from the flag list to
# make the message appear unread in other IMAP clients
imap.append(IMAP_MAILBOX, msg.to_s("\r\n"), [:Seen], created)

Randomized primary keys in ActiveRecord

One of the easiest means of cracking a naively-implemented Rails application (or any RDBMS-backed application with auto-incremented primary keys) is to simply alter site URLs and request parameters with the assumption that their IDs will be sequential.

For example, if a user sees a URL like the following in their location bar:

http://example.com/post/2705/comments

They could easily replace the number 2705 with, say, 2706, and see comments for that post. Of course, you’ve already added explicit permissions checks to every controller method that insure such access will never happen, but we all know how easy it can be to forget to audit each and every method for ID-traversal attempts.

Furthermore, using simple sequential IDs exposes other potentially-useful information to would-be attackers. They can see, for example, how many users, data objects, etc., are in active use on your site, and perhaps even reverse-engineer more of your database schema in order to plan SQL-injection or XSS attacks.

Actually using randomized keys does mean overriding the default ActiveRecord behavior, and may be tough to accomplish simply using ActiveRecord migrations. If your database is of a reasonable size, though, or you’re just getting started, it’s easy enough to do. First, you’ll need to decide on a random ID-generation algorithm.

The best way to generate “random” keys isn’t actually random at all. If you want to insure that no one can guess your keys, you’ll want to use a full-strength cryptographic hash. (See my FOSCON slides from last year for more info on that topic.)

If your primary keys are going to be exposed in your URLs at all, though, there are advantages to keeping them simple. Strong hashes generate long, difficult-to-type identifiers, so you’ll want to either slice them to get only a substring, or use a weaker algorithm which generates less randomness.

Regardless, you’ll need a helper method to generate the IDs, as well as some support in your models and migrations to glue it all together. Here’s a simple example, based on an “account invitation” implementation from an application I’m working on now:

# app/models/invite.rb
class Invite < ActiveRecord::Base
  include GenIdHelper

  def before_create
    self.id = gen_id
  end
end

# db/migrate/001_create_invites.rb
class CreateInvites < ActiveRecord::Migration
  def self.up
    create_table :invites do |t|
      t.column :id, :string, :limit => 8
      t.column :email, :string
      # ...
      t.timestamps
    end
  end

  def self.down
    drop_table :invites
  end
end

# lib/gen-id.rb
module GenIdHelper
  # Generates a pseudo-random string in hex format (0..9+A..F)
  # which contains chunk*16 bits of randomness.
  def gen_id(chunks=2)
    ("%04x"*chunks % ([nil]*chunks).map { rand(2**16) }).upcase
  end
end

The end result will be that newly-created instances of the Invite class will have an ID generated by gen_id, and will be much harder for anyone to guess by simply replacing URL components or POST values.

These random IDs can also be considered another form of identification for users. Basically, if they have received the random ID by some trusted channel, (say, SMS message, or snail-mail) it can be treated as a secondary authentication mechanism when creating a new account, performing a password reset, or proving their real world identity.

Ruby is my anti-drug

The following is an actual line from my shell transcript today:

sudo gem install crack

Hee-larious.

ActiveLdap, SASL, GSSAPI, and pain

I just wasted a day and a half banging my head against this problem, and while I suspect there are probably only about a half-dozen other sites on the planet that are likely to encounter this problem, I wanted to write down the solution. So, just in case anyone else has been furiously Googling for some combination of “ActiveLdap SASL GSSAPI bind connection error”, here’s one possible solution.

We use MIT Kerberos, OpenLDAP, and Cyrus SASL to provide single-sign-on across our network services at Reed. I’ve been working for a while to port legacy Perl-based systems over to Ruby, and using ActiveLdap for much of that work, but have hit a snag that limits its utility to use in many cases: namely, that GSSAPI-mech SASL binds fail if there is no corresponding LDAP directory entry for the principal under which you’re doing the bind.

Let me explain a bit of background:

OpenLDAP ACLs allow you to specify something like the following:

authz-regexp
uid=(.*),cn=gssapi,cn=auth

This basically says, “for any principal that our authentication backend accepts, treat them as a valid LDAP entity with the DN ‘uid=[principal-name],cn=gssapi,cn=auth’”. This is incredibly handy when coupled with Kerberos keytab files, as it lets us get the same basic benefit as certificate-based authentication without maintaining a certificate authority. (As an aside, we do actually maintain a small CA setup, but since the CA data lives on an external drive in a locked cabinet, rolling a new cert is a huge pain compared to creating a new keytab from kadmin.)

This is all well and good, and lets us set up background processes which have keytab-based privileges to selectively read and edit protected attributes on our directory, without putting passwords into configuration files or source code. It also means we don’t have to create a full-fledged directory entry for every little background service which may need to authenticate.

Unfortunately, ActiveLdap is unable to determine that it has successfully bound to the directory if the SASL GSSAPI principal it uses to bind doesn’t have a corresponding entry. It just loops over the reconnect method until the configured number of attempts is reached, then falls back to an anonymous bind.

If all of that was gibberish to you, rest easy; like I said, our particular mixture of infrastructure and directory-maintenance practices is pretty rare, especially outside academia, so you’ll probably never have to worry about any of this.