Skip to content

openid authentication

locks edited this page Sep 25, 2011 · 4 revisions

OpenID Authentication
In Camping, sometimes you want to be able to identify people uniquely and safely, but nobody really wants to write yet another registration and login form and email validation routine and password recovery form and buy an SSL certificate so that people don’t transmit their passwords to your app in plaintext. So, lets use OpenID instead! With OpenID all you need is a chunk of code in your camping controller, and a login page. Oh, and you’ll need to gem install ruby-openid. :)

The controller code

class Login < R '/openid'
  def get
    require 'openid'
    require 'openid/extensions/sreg'
    OpenID::Util.logger.sev_threshold = Logger::WARN
    
    # return to login if canceled
    return redirect('/') if input['openid.mode'] == 'cancel'
    
    this_url = URL(Login).to_s
    unless input.finish.to_s == '1'
      # start doing the auth here
      begin
        @state.openid_request = Hash.new
        oid_request = OpenID::Consumer.new(@state.openid_request, nil).begin(input.identity)
        # start sreg
        sreg = OpenID::SReg::Request.new
        sreg.request_fields(['nickname', 'fullname'], false)
        oid_request.add_extension(sreg)
        oid_request.return_to_args['finish'] = '1'
        redirect(oid_request.redirect_url(URL('/').to_s, this_url))
      rescue OpenID::DiscoveryFailure
        'Couldn\\'t find an OpenID at that address, are you sure it is one?'
      end
    else
      # finish the auth here
      response = OpenID::Consumer.new(@state.openid_request || {}, nil).complete(input, this_url)
      @state.delete('openid_request')
      case response.status
      when OpenID::Consumer::SUCCESS
        @state.identity = response.identity_url.to_s
        # start sreg
        sreg = OpenID::SReg::Response.from_success_response(response)
        unless sreg.empty?
          @state.default_username = sreg['fullname'] || sreg['nickname'] || nil
        end
        # end sreg
        grab_avatar
        when_done = @cookies.once_logged_in
        @cookies.delete('once_logged_in')
        redirect(when_done || Home)
      when OpenID::Consumer::FAILURE
        'The OpenID thing doesn\\'t think you really are that person, they said: ' + response.message
      else
        'Crazy response is crazy: ' + response.inspect
      end
    end
  end
  def post; get; end
end

This assumes you have a controller named Home where you want to send users once logged in. You can that to whatever of course. You can also have it load other SReg (Simple Registration) fields by adding them to the list in the first half of this code. This gives the user an opportunity in most cases to send you that information by simply clicking a button or checking a box, though be aware they are also able to login without sending this information, and that some OpenID providers do not support it at all.

Now in your other controllers, you can simply add code along the lines of return redirect(LoginPage) unless @state.identity, or you can build more complex helper’s which set the once logged in cookie and display the login page. :)

Clone this wiki locally