Class: Rack::Auth::OpenID

Inherits:
AbstractHandler show all
Defined in:
lib/rack/auth/openid.rb

Overview

Rack::Auth::OpenID provides a simple method for permitting openid based logins. It requires the ruby-openid lib from janrain to operate, as well as some method of session management of a Hash type.

After a transaction, the response status object is stored in the environment at rack.auth.openid.status, which can be used in the followup block or in a wrapping application to accomplish additional data maniipulation.

NOTE: Due to the amount of data that ruby-openid stores in the session, Rack::Session::Cookie may fault.

A hash of data is stored in the session hash at the key of :openid. The fully canonicalized identity url is stored within at ‘identity’. Extension data from ‘openid.sreg.nickname’ would be stored as { ‘nickname’ => value }.

NOTE: To my knowledge there is no collision at this point from storage of this manner, if there is please let me know so I may adjust this app to cope. NOTE: This rack application is only compatible with the 1.x.x versions of the ruby-openid library. If rubygems is loaded at require time of this app, the specification will be made. If it is not then the ‘openid’ library will be required, and will fail if it is not compatible.

Constant Summary collapse

OIDStore =

Required for ruby-openid

::OpenID::MemoryStore.new

Instance Attribute Summary

Attributes inherited from AbstractHandler

#realm

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ OpenID

A Hash of options is taken as it’s single initializing argument. String keys are taken to be openid protocol extension namespaces.

For example: 'sreg' => { 'required' => # 'nickname' }

Other keys are taken as options for Rack::Auth::OpenID, normally Symbols. Only :return is required. :trust is highly recommended to be set.

  • :return defines the url to return to after the client authenticates with the openid service provider. Should point to where this app is mounted. (ex: ‘mysite.com/openid’)

  • :trust defines the url identifying the site they are actually logging into. (ex: ‘mysite.com/’)

  • :session_key defines the key to the session hash in the env. (by default it uses ‘rack.session’)

Raises:

  • (ArgumentError)


53
54
55
56
57
58
59
60
61
# File 'lib/rack/auth/openid.rb', line 53

def initialize(options={})
  raise ArgumentError, 'No return url provided.'  unless options[:return]
  warn  'No trust url provided.'  unless options[:trust]
  options[:trust] ||= options[:return]

  @options  = {
    :session_key => 'rack.session'
  }.merge(options)
end

Instance Method Details

#auth_failObject



106
107
108
109
# File 'lib/rack/auth/openid.rb', line 106

def auth_fail
  @options.
    fetch :auth_fail, [500, {'Content-Type'=>'text/plain'},'Foreign server failure.']
end

#bad_loginObject



110
111
112
113
# File 'lib/rack/auth/openid.rb', line 110

def 
  @options.
    fetch :bad_login, [401, {'Content-Type'=>'text/plain'},'Identification has failed.']
end

#call(env) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rack/auth/openid.rb', line 63

def call(env)
  request = Rack::Request.new env
  return no_session unless session = request.env[@options[:session_key]]
  resp = if request.GET['openid.mode']
           finish session, request.GET, env
         elsif request.GET['openid_url']
           check session, request.GET['openid_url'], env
         else
           bad_request
         end
end

#check(session, oid_url, env) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rack/auth/openid.rb', line 75

def check(session, oid_url, env)
  consumer = ::OpenID::Consumer.new session, OIDStore
  oid = consumer.begin oid_url
  return auth_fail unless oid.status == ::OpenID::SUCCESS
  @options.each do |ns,s|
    next unless ns.is_a? String
    s.each {|k,v| oid.add_extension_arg(ns, k, v) }
  end
  r_url = @options.fetch :return do |k| request.url end
  t_url = @options.fetch :trust
  env['rack.auth.openid.status'] = oid
  return 303, {'Location'=>oid.redirect_url( t_url, r_url )}, []
end

#finish(session, params, env) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/rack/auth/openid.rb', line 89

def finish(session, params, env)
  consumer = ::OpenID::Consumer.new session, OIDStore
  oid = consumer.complete params
  return  unless oid.status == ::OpenID::SUCCESS
  session[:openid] = {'identity' => oid.identity_url}
  @options.each do |ns,s|
    next unless ns.is_a? String
    oid.extension_response(ns).each{|k,v| session[k]=v }
  end
  env['rack.auth.openid.status'] = oid
  return 303, {'Location'=>@options[:trust]}, []
end

#no_sessionObject



102
103
104
105
# File 'lib/rack/auth/openid.rb', line 102

def no_session
  @options.
    fetch :no_session, [500,{'Content-Type'=>'text/plain'},'No session available.']
end