zendesk_remote_auth gem makes Zendesk SSO easy!

I extracted how we are doing Zendesk remote authentication from an app at Dealer Ignition, and stuck it in a small gem for your enjoyment. You can find it on GitHub.

Installation and Setup

Install:

gem install tobias-zendesk_remote_auth

Setup:

You will need to give the gem your token and authentication url, perhaps in an initializer:

Zendesk::RemoteAuth.token = 'YOUR-TOKEN'
Zendesk::RemoteAuth.auth_url = 'https://yourcompany.zendesk.com/access/remote/'

and config the gem in environment.rb (if using rails):

config.gem 'tobias-zendesk_remote_auth', :lib => 'zendesk_remote_auth', :source => http://gems.github.com'

Usage

Mixin the Zendesk::RemoteAuthHelper module wherever needed, then call:

zendesk_remote_auth_url(:name => 'user name',
                        :email => 'user email',
                        <optional params>)

This will return a url you can redirect the user to to log them in to your zendesk account.

As a convenience, you can pass a user object to zendesk_remote_auth_url:

zendesk_remote_auth_url(user)

This user must respond_to? :name and :email, and its :id will be used as the :external_id (making it useless with user objects that return an ephemeral object_id, but works well with ActiveRecord and the like). If the user object responds to :zendesk_organization, that will be used as the :o rganization for the call.

This method will generate and include the hash of the parameters for you if necessary.

Example Auth Controller

Here is an example controller that handles login and logout for zendesk:

# Uses restful-authentication style auth. 
# 
# Define the following in routes.rb:
# map.with_options :controller => 'zendesk_auth' do |zd|
#   zd.connect '/zendesk/authorize', :action => 'authorize'
#   zd.connect '/zendesk/logout', :action => 'logout'
# end
class ZendeskAuthController < ApplicationController
    include Zendesk::RemoteAuthHelper
     
    skip_before_filter :login_required, :only => :logout
     
    def authorize
        redirect_to zendesk_remote_auth_url(current_user)
    end
     
    def logout
        redirect_to logout_url
    end
     
    protected
    def login_required
        if !logged_in?
            flash[:notice] = 'You must log in to access the support site.'
            store_location
            redirect_to login_path
        end
    end
end

RAILS_ROOT/app Organization

As an app grows, so does the amount of files in app/models. Here is a simple tip to help reduce the clutter: move mailers, observers, and sweepers out of app/models into app/mailers, app/observers, and app/sweepers, respectively. For rails to still load them, you will need to modify config/environment.rb:

# clean up app/models a bit
%w{mailers observers sweepers}.each do |dir|
    config.load_paths << "#{RAILS_ROOT}/app/#{dir}"
end

As a bonus, you can now automatically record your observers with ActiveRecord instead of having to add them individually in environment.rb:

config.active_record.observers = Dir.glob("#{RAILS_ROOT}/app/observers/*.rb").collect do |filename|
    filename.split('/').last.split('.').first.to_sym
end
One issue with this reorganization is that the generators will continue to create mailers, observers, and sweepers in app/models. For me, that is not a big deal – I don’t create them often, and manually move them after generation. I suspect it would be trivial to adjust the generators to use the new path, but have not looked in to it.

Restarting a hobby

In my youth (aka when I was 30) I ran a marathon, and had not run since until today.

My entire life, running is something I would do for a while and really enjoy, only to walk (ha!) away from it for a while. Life would get it the way (I would move, a new job would keep me too busy, {insert any other excuse here}). But then I would remember that I enjoyed it, and lace up again.

This latest break of five years since the marathon has been the longest. I have been considering running again for the last few weeks, but have had reservations: the narrow road I live on isn’t safe for running, I’m too busy with work and a new baby, {insert any other excuse here}. So when a friend called me up and asked me if I wanted to run the Outer Banks Marathon in November, I decided to go for a trial run this morning.

But first, to prepare! I need shoes, and shorts, and a fancy shirt; running socks, a gps, a smaller ipod, a runners log book. A couple of days ago I read Chad Fowler’s article on this exact situation: where we plan a new hobby, and instead of just doing it, we buy all the tools we need as a way to feel like we are making progress, instead of just doing it. I know I’ve done that – in my recent quest to learn to play guitar, I’ve accumulated: a guitar, a gig bag, a stand, two tuners, a capo, and a stack of books, but I don’t yet really know how to play. After reading Chad’s article, I decided to be more mindful of that tendency. I resisted the urge to buy anything for running, at least until I’m actually doing it on a regular schedule (and then all I’ll really need is a new pair of shoes). Last night, I gave in to the urge and started writing a Sinatra based running log application. I told myself I was doing it to learn Sinatra better, and to learn MongoDB, but did I really do it to feel like a runner?

server_remote gem

I just re-released my server_remote plugin as a gem server_remote on github. I converted it to a gem to make it easier to use in multiple apps, and to make it easier to update (see here for the blog entry on the (now obselete) plugin).

It is a gem that provides support for running commands on remote server. Once set up, it provides commands via script/remote:

  • remote shell – same as ssh’ing to the server (this is the default command, so it can be called with just remote)
  • remote console – executes a script/console on the server
  • remote logtail – executes tail -f log/<environment>.log on the server
  • remote cmd <some command> executes command on the server, displaying the result. It cd‘s to the remote app root first.
  • remote scp <local_file> :<remote_file> provides scp. Prefix remote files with ‘:’
Configuration is in config/server_remote.yml, and is grouped into profiles.

Here is the output of remote usage:

Executes commands on a remote server over ssh. Configuration is in:
/Users/tobias/customers/DealerIgnition/dealer_ignition/script/../config/server_remote.yml
 
You can override the profile used with -p profile. The default profile is: app
 
Learn more in the readme:
/opt/local/lib/ruby/gems/1.8/gems/tobias-server_remote-0.2.0/lib/server_remote/../../README.textile
 
remote commands are:
 
DEFAULT COMMAND   shell
 
cmd               executes an arbitrary command on the server after a cd to the app path
commands          List all 'remote' commands
console           executes remote console
help              Provide help documentation for a command
logtail           executes remote tail -f on the log
scp               copies files over scp (prefix remote files with ':')
shell             executes remote shell
usage             prints usage message
 
For help on a particular command, use 'remote help COMMAND'.

It uses remi’s simplecli gem.

I plan to add other commands as needed, or you can open up Remote::Commands and add your own.

Installation

You will need to install the gem (only once), then setup any apps where you want to use it.

sudo gem install tobias-server_remote --source http://gems.github.com/
server_remotify path_to_app

credit_card_validator gem

I recently published a gem that provides credit card validation. It is basically a ruby port of the javascript credit card validator by Thomas Fuchs (madrobby).

Usage:

  CreditCardValidator::Validator.valid?('1111 2222 3333 4444')
 
# allow test numbers to be valid (for development) 
CreditCardValidator::Validator.options[:test_numbers_are_valid] = true
CreditCardValidator::Validator.valid?('1111 2222 3333 4444')
 
# limit the card types you allow
CreditCardValidator::Validator.options[:allowed_card_types] = [:visa, :mastercard]
CreditCardValidator::Validator.valid?('1111 2222 3333 4444')

Supported card types:

  :amex, :discover, :diners_club, :master_card, :visa

Whitespace is stripped from the number automatically.

The following things are tested:

1. does the luhn validation code add up? (see http://en.wikipedia.org/wiki/Luhn_algorithm)

2. does the number range and length seem right? (see http://en.wikipedia.org/wiki/Bank_card_number)

3. is it one of several well-known test numbers?

Note: this only validates that the number is of a valid format, it does not check if it is an actual credit card number. You will need to talk to your payment gateway to learn that.

You can also use the validator to learn about the type of the card:

  # gives the type back as a string (visa, master_card, etc)
CreditCardValidator::Validator.card_type(number)
 
CreditCardValidator::Validator.is_visa?(number)
CreditCardValidator::Validator.is_master_card?(number)
# etc. - works for all of the supported card types
 
CreditCardValidator::Validator.is_allowed_card_type?(number)

To Install:

gem install tobias-credit_card_validator --source http://gems.github.com

The source is available on github