Update OpenID authentication plugin to latest version
[rails.git] / vendor / plugins / open_id_authentication / lib / open_id_authentication.rb
1 require 'uri'
2 require 'openid'
3 require 'rack/openid'
4
5 module OpenIdAuthentication
6   def self.new(app)
7     store = OpenIdAuthentication.store
8     if store.nil?
9       Rails.logger.warn "OpenIdAuthentication.store is nil. Using in-memory store."
10     end
11
12     ::Rack::OpenID.new(app, OpenIdAuthentication.store)
13   end
14
15   def self.store
16     @@store
17   end
18
19   def self.store=(*store_option)
20     store, *parameters = *([ store_option ].flatten)
21
22     @@store = case store
23     when :memory
24       require 'openid/store/memory'
25       OpenID::Store::Memory.new
26     when :file
27       require 'openid/store/filesystem'
28       OpenID::Store::Filesystem.new(Rails.root.join('tmp/openids'))
29     when :memcache
30       require 'memcache'
31       require 'openid/store/memcache'
32       OpenID::Store::Memcache.new(MemCache.new(parameters))
33     else
34       store
35     end
36   end
37
38   self.store = nil
39
40   class Result
41     ERROR_MESSAGES = {
42       :missing      => "Sorry, the OpenID server couldn't be found",
43       :invalid      => "Sorry, but this does not appear to be a valid OpenID",
44       :canceled     => "OpenID verification was canceled",
45       :failed       => "OpenID verification failed",
46       :setup_needed => "OpenID verification needs setup"
47     }
48
49     def self.[](code)
50       new(code)
51     end
52
53     def initialize(code)
54       @code = code
55     end
56
57     def status
58       @code
59     end
60
61     ERROR_MESSAGES.keys.each { |state| define_method("#{state}?") { @code == state } }
62
63     def successful?
64       @code == :successful
65     end
66
67     def unsuccessful?
68       ERROR_MESSAGES.keys.include?(@code)
69     end
70
71     def message
72       ERROR_MESSAGES[@code]
73     end
74   end
75
76   protected
77     # The parameter name of "openid_identifier" is used rather than
78     # the Rails convention "open_id_identifier" because that's what
79     # the specification dictates in order to get browser auto-complete
80     # working across sites
81     def using_open_id?(identifier = nil) #:doc:
82       identifier ||= open_id_identifier
83       !identifier.blank? || request.env[Rack::OpenID::RESPONSE]
84     end
85
86     def authenticate_with_open_id(identifier = nil, options = {}, &block) #:doc:
87       identifier ||= open_id_identifier
88
89       if request.env[Rack::OpenID::RESPONSE]
90         complete_open_id_authentication(&block)
91       else
92         begin_open_id_authentication(identifier, options, &block)
93       end
94     end
95
96   private
97     def open_id_identifier
98       params[:openid_identifier] || params[:openid_url]
99     end
100
101     def begin_open_id_authentication(identifier, options = {})
102       options[:identifier] = identifier
103       value = Rack::OpenID.build_header(options)
104       response.headers[Rack::OpenID::AUTHENTICATE_HEADER] = value
105       head :unauthorized
106     end
107
108     def complete_open_id_authentication
109       response   = request.env[Rack::OpenID::RESPONSE]
110       identifier = response.display_identifier
111
112       case response.status
113       when OpenID::Consumer::SUCCESS
114         yield Result[:successful], identifier,
115           OpenID::SReg::Response.from_success_response(response)
116       when :missing
117         yield Result[:missing], identifier, nil
118       when :invalid
119         yield Result[:invalid], identifier, nil
120       when OpenID::Consumer::CANCEL
121         yield Result[:canceled], identifier, nil
122       when OpenID::Consumer::FAILURE
123         yield Result[:failed], identifier, nil
124       when OpenID::Consumer::SETUP_NEEDED
125         yield Result[:setup_needed], response.setup_url, nil
126       end
127     end
128 end