For anyone who stumbles upon this question in the future (like I did), here's a nice workaround for a composite primary key in Eloquent.
This goes at the top of your model class:
protected $primaryKey = array('key1', 'key2');
Then you override the save() method on your model with this:
public function save(array $options = array())
{
    if(!is_array($this->getKeyName()))
        return parent::save($options);
    // Fire Event for others to hook
    if($this->fireModelEvent('saving') === false)
        return false;
    // Prepare query for inserting or updating
    $query = $this->newQueryWithoutScopes();
    // Perform Update
    if ($this->exists) {
        if (count($this->getDirty()) > 0) {
            // Fire Event for others to hook
            if ($this->fireModelEvent('updating') === false)
                return false;
            // Touch the timestamps
            if ($this->timestamps)
                $this->updateTimestamps();
            //
            // START FIX
            //
            // Convert primary key into an array if it's a single value
            $primary = (count($this->getKeyName()) > 1) ? $this->getKeyName() : [$this->getKeyName()];
            // Fetch the primary key(s) values before any changes
            $unique = array_intersect_key($this->original, array_flip($primary));
            // Fetch the primary key(s) values after any changes
            $unique = !empty($unique) ? $unique : array_intersect_key($this->getAttributes(), array_flip($primary));
            // Fetch the element of the array if the array contains only a single element
            $unique = (count($unique) <> 1) ? $unique : reset($unique);
            // Apply SQL logic
            $query->where($unique);
            //
            // END FIX
            //
            // Update the records
            $query->update($this->getDirty());
            // Fire an event for hooking into
            $this->fireModelEvent('updated', false);
        }
    // Perform Insert
    } else {
        // Fire an event for hooking into
        if ($this->fireModelEvent('creating') === false)
            return false;
        // Touch the timestamps
        if ($this->timestamps)
            $this->updateTimestamps();
        // Retrieve the attributes
        $attributes = $this->attributes;
        if ($this->incrementing && !is_array($this->getKeyName()))
            $this->insertAndSetId($query, $attributes);
        else
            $query->insert($attributes);
        // Set exists to true in case someone tries to update it during an event
        $this->exists = true;
        // Fire an event for hooking into
        $this->fireModelEvent('created', false);
    }
    // Fires an event
    $this->fireModelEvent('saved', false);
    // Sync
    $this->original = $this->attributes;
    // Touches all relations
    if (array_get($options, 'touch', true))
        $this->touchOwners();
    return true;
}
Original source: https://github.com/laravel/framework/issues/5517#issuecomment-52996610
Update 2016-05-03
My new favorite way to do this:
How I can put composite keys in models in Laravel 5?