tfe-authlogic_openid 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +25 -0
- data/MIT-LICENSE +20 -0
- data/Manifest.txt +38 -0
- data/README.rdoc +93 -0
- data/Rakefile +137 -0
- data/init.rb +1 -0
- data/lib/authlogic_openid.rb +6 -0
- data/lib/authlogic_openid/acts_as_authentic.rb +174 -0
- data/lib/authlogic_openid/session.rb +125 -0
- data/lib/authlogic_openid/version.rb +51 -0
- data/test/acts_as_authentic_test.rb +105 -0
- data/test/fixtures/users.yml +9 -0
- data/test/libs/open_id_authentication/CHANGELOG +35 -0
- data/test/libs/open_id_authentication/README +231 -0
- data/test/libs/open_id_authentication/Rakefile +22 -0
- data/test/libs/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb +11 -0
- data/test/libs/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb +20 -0
- data/test/libs/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb +26 -0
- data/test/libs/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb +11 -0
- data/test/libs/open_id_authentication/init.rb +18 -0
- data/test/libs/open_id_authentication/lib/open_id_authentication.rb +244 -0
- data/test/libs/open_id_authentication/lib/open_id_authentication/association.rb +9 -0
- data/test/libs/open_id_authentication/lib/open_id_authentication/db_store.rb +55 -0
- data/test/libs/open_id_authentication/lib/open_id_authentication/mem_cache_store.rb +73 -0
- data/test/libs/open_id_authentication/lib/open_id_authentication/nonce.rb +5 -0
- data/test/libs/open_id_authentication/lib/open_id_authentication/request.rb +23 -0
- data/test/libs/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb +20 -0
- data/test/libs/open_id_authentication/tasks/open_id_authentication_tasks.rake +30 -0
- data/test/libs/open_id_authentication/test/mem_cache_store_test.rb +151 -0
- data/test/libs/open_id_authentication/test/normalize_test.rb +32 -0
- data/test/libs/open_id_authentication/test/open_id_authentication_test.rb +46 -0
- data/test/libs/open_id_authentication/test/status_test.rb +14 -0
- data/test/libs/open_id_authentication/test/test_helper.rb +17 -0
- data/test/libs/rails_trickery.rb +41 -0
- data/test/libs/user.rb +3 -0
- data/test/libs/user_session.rb +2 -0
- data/test/session_test.rb +32 -0
- data/test/test_helper.rb +78 -0
- metadata +107 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the open_id_authentication plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the open_id_authentication plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'OpenIdAuthentication'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class <%= class_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :open_id_authentication_associations, :force => true do |t|
|
4
|
+
t.integer :issued, :lifetime
|
5
|
+
t.string :handle, :assoc_type
|
6
|
+
t.binary :server_url, :secret
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table :open_id_authentication_nonces, :force => true do |t|
|
10
|
+
t.integer :timestamp, :null => false
|
11
|
+
t.string :server_url, :null => true
|
12
|
+
t.string :salt, :null => false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.down
|
17
|
+
drop_table :open_id_authentication_associations
|
18
|
+
drop_table :open_id_authentication_nonces
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class <%= class_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
drop_table :open_id_authentication_settings
|
4
|
+
drop_table :open_id_authentication_nonces
|
5
|
+
|
6
|
+
create_table :open_id_authentication_nonces, :force => true do |t|
|
7
|
+
t.integer :timestamp, :null => false
|
8
|
+
t.string :server_url, :null => true
|
9
|
+
t.string :salt, :null => false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :open_id_authentication_nonces
|
15
|
+
|
16
|
+
create_table :open_id_authentication_nonces, :force => true do |t|
|
17
|
+
t.integer :created
|
18
|
+
t.string :nonce
|
19
|
+
end
|
20
|
+
|
21
|
+
create_table :open_id_authentication_settings, :force => true do |t|
|
22
|
+
t.string :setting
|
23
|
+
t.binary :value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
if config.respond_to?(:gems)
|
2
|
+
config.gem 'ruby-openid', :lib => 'openid', :version => '>=2.0.4'
|
3
|
+
else
|
4
|
+
begin
|
5
|
+
require 'openid'
|
6
|
+
rescue LoadError
|
7
|
+
begin
|
8
|
+
gem 'ruby-openid', '>=2.0.4'
|
9
|
+
rescue Gem::LoadError
|
10
|
+
puts "Install the ruby-openid gem to enable OpenID support"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
config.to_prepare do
|
16
|
+
OpenID::Util.logger = Rails.logger
|
17
|
+
ActionController::Base.send :include, OpenIdAuthentication
|
18
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'openid/extensions/sreg'
|
3
|
+
require 'openid/extensions/ax'
|
4
|
+
require 'openid/store/filesystem'
|
5
|
+
|
6
|
+
require File.dirname(__FILE__) + '/open_id_authentication/association'
|
7
|
+
require File.dirname(__FILE__) + '/open_id_authentication/nonce'
|
8
|
+
require File.dirname(__FILE__) + '/open_id_authentication/db_store'
|
9
|
+
require File.dirname(__FILE__) + '/open_id_authentication/mem_cache_store'
|
10
|
+
require File.dirname(__FILE__) + '/open_id_authentication/request'
|
11
|
+
require File.dirname(__FILE__) + '/open_id_authentication/timeout_fixes' if OpenID::VERSION == "2.0.4"
|
12
|
+
|
13
|
+
module OpenIdAuthentication
|
14
|
+
OPEN_ID_AUTHENTICATION_DIR = RAILS_ROOT + "/tmp/openids"
|
15
|
+
|
16
|
+
def self.store
|
17
|
+
@@store
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.store=(*store_option)
|
21
|
+
store, *parameters = *([ store_option ].flatten)
|
22
|
+
|
23
|
+
@@store = case store
|
24
|
+
when :db
|
25
|
+
OpenIdAuthentication::DbStore.new
|
26
|
+
when :mem_cache
|
27
|
+
OpenIdAuthentication::MemCacheStore.new(*parameters)
|
28
|
+
when :file
|
29
|
+
OpenID::Store::Filesystem.new(OPEN_ID_AUTHENTICATION_DIR)
|
30
|
+
else
|
31
|
+
raise "Unknown store: #{store}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
self.store = :db
|
36
|
+
|
37
|
+
class InvalidOpenId < StandardError
|
38
|
+
end
|
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
|
+
# normalizes an OpenID according to http://openid.net/specs/openid-authentication-2_0.html#normalization
|
77
|
+
def self.normalize_identifier(identifier)
|
78
|
+
# clean up whitespace
|
79
|
+
identifier = identifier.to_s.strip
|
80
|
+
|
81
|
+
# if an XRI has a prefix, strip it.
|
82
|
+
identifier.gsub!(/xri:\/\//i, '')
|
83
|
+
|
84
|
+
# dodge XRIs -- TODO: validate, don't just skip.
|
85
|
+
unless ['=', '@', '+', '$', '!', '('].include?(identifier.at(0))
|
86
|
+
# does it begin with http? if not, add it.
|
87
|
+
identifier = "http://#{identifier}" unless identifier =~ /^http/i
|
88
|
+
|
89
|
+
# strip any fragments
|
90
|
+
identifier.gsub!(/\#(.*)$/, '')
|
91
|
+
|
92
|
+
begin
|
93
|
+
uri = URI.parse(identifier)
|
94
|
+
uri.scheme = uri.scheme.downcase # URI should do this
|
95
|
+
identifier = uri.normalize.to_s
|
96
|
+
rescue URI::InvalidURIError
|
97
|
+
raise InvalidOpenId.new("#{identifier} is not an OpenID identifier")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
return identifier
|
102
|
+
end
|
103
|
+
|
104
|
+
# deprecated for OpenID 2.0, where not all OpenIDs are URLs
|
105
|
+
def self.normalize_url(url)
|
106
|
+
ActiveSupport::Deprecation.warn "normalize_url has been deprecated, use normalize_identifier instead"
|
107
|
+
self.normalize_identifier(url)
|
108
|
+
end
|
109
|
+
|
110
|
+
protected
|
111
|
+
def normalize_url(url)
|
112
|
+
OpenIdAuthentication.normalize_url(url)
|
113
|
+
end
|
114
|
+
|
115
|
+
def normalize_identifier(url)
|
116
|
+
OpenIdAuthentication.normalize_identifier(url)
|
117
|
+
end
|
118
|
+
|
119
|
+
# The parameter name of "openid_identifier" is used rather than the Rails convention "open_id_identifier"
|
120
|
+
# because that's what the specification dictates in order to get browser auto-complete working across sites
|
121
|
+
def using_open_id?(identity_url = nil) #:doc:
|
122
|
+
identity_url ||= params[:openid_identifier] || params[:openid_url]
|
123
|
+
!identity_url.blank? || params[:open_id_complete]
|
124
|
+
end
|
125
|
+
|
126
|
+
def authenticate_with_open_id(identity_url = nil, options = {}, &block) #:doc:
|
127
|
+
identity_url ||= params[:openid_identifier] || params[:openid_url]
|
128
|
+
|
129
|
+
if params[:open_id_complete].nil?
|
130
|
+
begin_open_id_authentication(identity_url, options, &block)
|
131
|
+
else
|
132
|
+
complete_open_id_authentication(&block)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
def begin_open_id_authentication(identity_url, options = {})
|
138
|
+
identity_url = normalize_identifier(identity_url)
|
139
|
+
return_to = options.delete(:return_to)
|
140
|
+
method = options.delete(:method)
|
141
|
+
|
142
|
+
options[:required] ||= [] # reduces validation later
|
143
|
+
options[:optional] ||= []
|
144
|
+
|
145
|
+
open_id_request = open_id_consumer.begin(identity_url)
|
146
|
+
add_simple_registration_fields(open_id_request, options)
|
147
|
+
add_ax_fields(open_id_request, options)
|
148
|
+
|
149
|
+
redirect_to(open_id_redirect_url(open_id_request, return_to, method))
|
150
|
+
rescue OpenIdAuthentication::InvalidOpenId => e
|
151
|
+
yield Result[:invalid], identity_url, nil
|
152
|
+
rescue OpenID::OpenIDError, Timeout::Error => e
|
153
|
+
logger.error("[OPENID] #{e}")
|
154
|
+
yield Result[:missing], identity_url, nil
|
155
|
+
end
|
156
|
+
|
157
|
+
def complete_open_id_authentication
|
158
|
+
params_with_path = params.reject { |key, value| request.path_parameters[key] }
|
159
|
+
params_with_path.delete(:format)
|
160
|
+
open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params_with_path, requested_url) }
|
161
|
+
identity_url = normalize_identifier(open_id_response.display_identifier) if open_id_response.display_identifier
|
162
|
+
|
163
|
+
case open_id_response.status
|
164
|
+
when OpenID::Consumer::SUCCESS
|
165
|
+
profile_data = {}
|
166
|
+
|
167
|
+
# merge the SReg data and the AX data into a single hash of profile data
|
168
|
+
[ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response|
|
169
|
+
if data_response.from_success_response( open_id_response )
|
170
|
+
profile_data.merge! data_response.from_success_response( open_id_response ).data
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
yield Result[:successful], identity_url, profile_data
|
175
|
+
when OpenID::Consumer::CANCEL
|
176
|
+
yield Result[:canceled], identity_url, nil
|
177
|
+
when OpenID::Consumer::FAILURE
|
178
|
+
yield Result[:failed], identity_url, nil
|
179
|
+
when OpenID::Consumer::SETUP_NEEDED
|
180
|
+
yield Result[:setup_needed], open_id_response.setup_url, nil
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def open_id_consumer
|
185
|
+
OpenID::Consumer.new(session, OpenIdAuthentication.store)
|
186
|
+
end
|
187
|
+
|
188
|
+
def add_simple_registration_fields(open_id_request, fields)
|
189
|
+
sreg_request = OpenID::SReg::Request.new
|
190
|
+
|
191
|
+
# filter out AX identifiers (URIs)
|
192
|
+
required_fields = fields[:required].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact
|
193
|
+
optional_fields = fields[:optional].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact
|
194
|
+
|
195
|
+
sreg_request.request_fields(required_fields, true) unless required_fields.blank?
|
196
|
+
sreg_request.request_fields(optional_fields, false) unless optional_fields.blank?
|
197
|
+
sreg_request.policy_url = fields[:policy_url] if fields[:policy_url]
|
198
|
+
open_id_request.add_extension(sreg_request)
|
199
|
+
end
|
200
|
+
|
201
|
+
def add_ax_fields( open_id_request, fields )
|
202
|
+
ax_request = OpenID::AX::FetchRequest.new
|
203
|
+
|
204
|
+
# look through the :required and :optional fields for URIs (AX identifiers)
|
205
|
+
fields[:required].each do |f|
|
206
|
+
next unless f =~ /^https?:\/\//
|
207
|
+
ax_request.add( OpenID::AX::AttrInfo.new( f, nil, true ) )
|
208
|
+
end
|
209
|
+
|
210
|
+
fields[:optional].each do |f|
|
211
|
+
next unless f =~ /^https?:\/\//
|
212
|
+
ax_request.add( OpenID::AX::AttrInfo.new( f, nil, false ) )
|
213
|
+
end
|
214
|
+
|
215
|
+
open_id_request.add_extension( ax_request )
|
216
|
+
end
|
217
|
+
|
218
|
+
def open_id_redirect_url(open_id_request, return_to = nil, method = nil)
|
219
|
+
open_id_request.return_to_args['_method'] = (method || request.method).to_s
|
220
|
+
open_id_request.return_to_args['open_id_complete'] = '1'
|
221
|
+
open_id_request.redirect_url(root_url, return_to || requested_url)
|
222
|
+
end
|
223
|
+
|
224
|
+
def requested_url
|
225
|
+
relative_url_root = self.class.respond_to?(:relative_url_root) ?
|
226
|
+
self.class.relative_url_root.to_s :
|
227
|
+
request.relative_url_root
|
228
|
+
"#{request.protocol}#{request.host_with_port}#{ActionController::Base.relative_url_root}#{request.path}"
|
229
|
+
end
|
230
|
+
|
231
|
+
def timeout_protection_from_identity_server
|
232
|
+
yield
|
233
|
+
rescue Timeout::Error
|
234
|
+
Class.new do
|
235
|
+
def status
|
236
|
+
OpenID::FAILURE
|
237
|
+
end
|
238
|
+
|
239
|
+
def msg
|
240
|
+
"Identity server timed out"
|
241
|
+
end
|
242
|
+
end.new
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'openid/store/interface'
|
2
|
+
|
3
|
+
module OpenIdAuthentication
|
4
|
+
class DbStore < OpenID::Store::Interface
|
5
|
+
def self.cleanup_nonces
|
6
|
+
now = Time.now.to_i
|
7
|
+
Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew])
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.cleanup_associations
|
11
|
+
now = Time.now.to_i
|
12
|
+
Association.delete_all(['issued + lifetime > ?',now])
|
13
|
+
end
|
14
|
+
|
15
|
+
def store_association(server_url, assoc)
|
16
|
+
remove_association(server_url, assoc.handle)
|
17
|
+
Association.create(:server_url => server_url,
|
18
|
+
:handle => assoc.handle,
|
19
|
+
:secret => assoc.secret,
|
20
|
+
:issued => assoc.issued,
|
21
|
+
:lifetime => assoc.lifetime,
|
22
|
+
:assoc_type => assoc.assoc_type)
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_association(server_url, handle = nil)
|
26
|
+
assocs = if handle.blank?
|
27
|
+
Association.find_all_by_server_url(server_url)
|
28
|
+
else
|
29
|
+
Association.find_all_by_server_url_and_handle(server_url, handle)
|
30
|
+
end
|
31
|
+
|
32
|
+
assocs.reverse.each do |assoc|
|
33
|
+
a = assoc.from_record
|
34
|
+
if a.expires_in == 0
|
35
|
+
assoc.destroy
|
36
|
+
else
|
37
|
+
return a
|
38
|
+
end
|
39
|
+
end if assocs.any?
|
40
|
+
|
41
|
+
return nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove_association(server_url, handle)
|
45
|
+
Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def use_nonce(server_url, timestamp, salt)
|
49
|
+
return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt)
|
50
|
+
return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew
|
51
|
+
Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt)
|
52
|
+
return true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'openid/store/interface'
|
3
|
+
|
4
|
+
module OpenIdAuthentication
|
5
|
+
class MemCacheStore < OpenID::Store::Interface
|
6
|
+
def initialize(*addresses)
|
7
|
+
@connection = ActiveSupport::Cache::MemCacheStore.new(addresses)
|
8
|
+
end
|
9
|
+
|
10
|
+
def store_association(server_url, assoc)
|
11
|
+
server_key = association_server_key(server_url)
|
12
|
+
assoc_key = association_key(server_url, assoc.handle)
|
13
|
+
|
14
|
+
assocs = @connection.read(server_key) || {}
|
15
|
+
assocs[assoc.issued] = assoc_key
|
16
|
+
|
17
|
+
@connection.write(server_key, assocs)
|
18
|
+
@connection.write(assoc_key, assoc, :expires_in => assoc.lifetime)
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_association(server_url, handle = nil)
|
22
|
+
if handle
|
23
|
+
@connection.read(association_key(server_url, handle))
|
24
|
+
else
|
25
|
+
server_key = association_server_key(server_url)
|
26
|
+
assocs = @connection.read(server_key)
|
27
|
+
return if assocs.nil?
|
28
|
+
|
29
|
+
last_key = assocs[assocs.keys.sort.last]
|
30
|
+
@connection.read(last_key)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def remove_association(server_url, handle)
|
35
|
+
server_key = association_server_key(server_url)
|
36
|
+
assoc_key = association_key(server_url, handle)
|
37
|
+
assocs = @connection.read(server_key)
|
38
|
+
|
39
|
+
return false unless assocs && assocs.has_value?(assoc_key)
|
40
|
+
|
41
|
+
assocs = assocs.delete_if { |key, value| value == assoc_key }
|
42
|
+
|
43
|
+
@connection.write(server_key, assocs)
|
44
|
+
@connection.delete(assoc_key)
|
45
|
+
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
|
49
|
+
def use_nonce(server_url, timestamp, salt)
|
50
|
+
return false if @connection.read(nonce_key(server_url, salt))
|
51
|
+
return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew
|
52
|
+
@connection.write(nonce_key(server_url, salt), timestamp, :expires_in => OpenID::Nonce.skew)
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def association_key(server_url, handle = nil)
|
58
|
+
"openid_association_#{digest(server_url)}_#{digest(handle)}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def association_server_key(server_url)
|
62
|
+
"openid_association_server_#{digest(server_url)}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def nonce_key(server_url, salt)
|
66
|
+
"openid_nonce_#{digest(server_url)}_#{digest(salt)}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def digest(text)
|
70
|
+
Digest::SHA1.hexdigest(text)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|