openid_active_record_store 1.0.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/README.rdoc +63 -0
- data/Rakefile +29 -0
- data/app/models/openid_abstract.rb +5 -0
- data/app/models/openid_association.rb +2 -0
- data/app/models/openid_nonce.rb +8 -0
- data/db/migrate/create_openid_associations.rb +22 -0
- data/db/migrate/create_openid_nonces.rb +17 -0
- data/lib/openid/store/active_record.rb +121 -0
- data/lib/openid_active_record_store.rb +33 -0
- data/test/openid_store_active_record_test.rb +237 -0
- data/test/test_helper.rb +24 -0
- metadata +91 -0
data/README.rdoc
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
= openid_active_record_store
|
2
|
+
|
3
|
+
http://rubygems.org/gems/openid_active_record_store
|
4
|
+
{Project}[http://rubygems.org/gems/openid_active_record_store]
|
5
|
+
{Wiki}[http://wiki.github.com/raggi/openid_active_record_store/]
|
6
|
+
{Source Code}[http://github.com/raggi/openid_active_record_store/]
|
7
|
+
{Issues}[http://github.com/raggi/openid_active_record_store/issues]
|
8
|
+
|
9
|
+
== DESCRIPTION:
|
10
|
+
|
11
|
+
A rails engine for OpenID/Omniauth that writes to ActiveRecord for the OpenID data. Forked from an old project by Kazuyoshi Tlacaelel.
|
12
|
+
|
13
|
+
== FEATURES/PROBLEMS:
|
14
|
+
|
15
|
+
* Simple
|
16
|
+
* Lowish test coverage
|
17
|
+
* Binary column may not work well with some adapters
|
18
|
+
|
19
|
+
== SYNOPSIS:
|
20
|
+
|
21
|
+
rake openid_active_record_store:install:migrations
|
22
|
+
rake db:migrate
|
23
|
+
|
24
|
+
# Omniauth example:
|
25
|
+
Rails.application.config.middleware.use(
|
26
|
+
OmniAuth::Strategies::GoogleApps,
|
27
|
+
OpenID::Store::ActiveRecord.new,
|
28
|
+
{ :name => 'example', :domain => 'example.org' }
|
29
|
+
)
|
30
|
+
|
31
|
+
== REQUIREMENTS:
|
32
|
+
|
33
|
+
* Rails 3+
|
34
|
+
* OpenID
|
35
|
+
|
36
|
+
== INSTALL:
|
37
|
+
|
38
|
+
* gem install openid_active_record_store
|
39
|
+
|
40
|
+
== LICENSE:
|
41
|
+
|
42
|
+
(The MIT License)
|
43
|
+
|
44
|
+
Copyright (c) 2011 Kazuyoshi Tlacaelel, James Tucker, Wildfire Interactive Inc
|
45
|
+
|
46
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
47
|
+
a copy of this software and associated documentation files (the
|
48
|
+
'Software'), to deal in the Software without restriction, including
|
49
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
50
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
51
|
+
permit persons to whom the Software is furnished to do so, subject to
|
52
|
+
the following conditions:
|
53
|
+
|
54
|
+
The above copyright notice and this permission notice shall be
|
55
|
+
included in all copies or substantial portions of the Software.
|
56
|
+
|
57
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
58
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
59
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
60
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
61
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
62
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
63
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rdoc/task'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the openid_store_active_record plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.ruby_opts << '-rubygems'
|
11
|
+
t.libs += %w[test]
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
t.warning = true
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Generate documentation for the openid_store_active_record plugin.'
|
18
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
19
|
+
rdoc.rdoc_dir = 'rdoc'
|
20
|
+
rdoc.title = 'OpenidStoreActiveRecord'
|
21
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
22
|
+
rdoc.rdoc_files.include('README')
|
23
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "build gem"
|
27
|
+
task :gem do
|
28
|
+
sh "gem build openid_active_record_store.gemspec"
|
29
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class CreateOpenidAssociations < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :openid_associations do |t|
|
5
|
+
t.datetime :issued_at
|
6
|
+
t.integer :lifetime
|
7
|
+
t.string :assoc_type
|
8
|
+
t.text :handle
|
9
|
+
t.binary :secret
|
10
|
+
|
11
|
+
t.string :target, :size => 32
|
12
|
+
t.text :server_url
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.down
|
19
|
+
drop_table :openid_associations
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreateOpenidNonces < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :openid_nonces do |t|
|
5
|
+
t.integer :timestamp
|
6
|
+
t.string :salt
|
7
|
+
t.string :target, :size => 32
|
8
|
+
t.text :server_url
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :openid_nonces
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'openid/util'
|
2
|
+
require 'openid/store/interface'
|
3
|
+
require 'openid/association'
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
module OpenID
|
7
|
+
module Store
|
8
|
+
class ActiveRecord < Interface
|
9
|
+
|
10
|
+
# Put a Association object into storage.
|
11
|
+
# When implementing a store, don't assume that there are any limitations
|
12
|
+
# on the character set of the server_url. In particular, expect to see
|
13
|
+
# unescaped non-url-safe characters in the server_url field.
|
14
|
+
def store_association(server_url, association)
|
15
|
+
OpenidAssociation.create!(
|
16
|
+
:server_url => server_url,
|
17
|
+
:target => targetize(server_url),
|
18
|
+
:handle => association.handle,
|
19
|
+
:secret => association.secret,
|
20
|
+
:issued_at => association.issued,
|
21
|
+
:lifetime => association.lifetime,
|
22
|
+
:assoc_type => association.assoc_type
|
23
|
+
)
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns a Association object from storage that matches
|
28
|
+
# the server_url. Returns nil if no such association is found or if
|
29
|
+
# the one matching association is expired. (Is allowed to GC expired
|
30
|
+
# associations when found.)
|
31
|
+
def get_association(server_url, handle=nil)
|
32
|
+
oas = OpenidAssociation.find_all_by_target targetize(server_url)
|
33
|
+
return nil if oas.empty?
|
34
|
+
unless handle.nil?
|
35
|
+
return nil unless oas.collect(&:handle).include? handle
|
36
|
+
return build_association(oas.find { |oa| oa.handle == handle })
|
37
|
+
end
|
38
|
+
oas.sort_by(&:issued_at).collect { |oa| build_association(oa) }.last
|
39
|
+
end
|
40
|
+
|
41
|
+
# If there is a matching association, remove it from the store and
|
42
|
+
# return true, otherwise return false.
|
43
|
+
def remove_association(server_url, handle)
|
44
|
+
oas = OpenidAssociation.find_all_by_target targetize(server_url)
|
45
|
+
return false unless oas.collect(&:handle).include? handle
|
46
|
+
oas.find_all { |oa| oa.handle == handle }.each(&:delete).size > 0
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return true if the nonce has not been used before, and store it
|
50
|
+
# for a while to make sure someone doesn't try to use the same value
|
51
|
+
# again. Return false if the nonce has already been used or if the
|
52
|
+
# timestamp is not current.
|
53
|
+
# You can use OpenID::Store::Nonce::SKEW for your timestamp window.
|
54
|
+
# server_url: URL of the server from which the nonce originated
|
55
|
+
# timestamp: time the nonce was created in seconds since unix epoch
|
56
|
+
# salt: A random string that makes two nonces issued by a server in
|
57
|
+
# the same second unique
|
58
|
+
def use_nonce(server_url, timestamp, salt)
|
59
|
+
return false if (timestamp - Time.now.to_i).abs > Nonce.skew
|
60
|
+
params = [timestamp, salt, targetize(server_url)]
|
61
|
+
return false if OpenidNonce.exists_by_target?(*params)
|
62
|
+
return create_nonce(server_url, timestamp, salt)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Remove expired nonces and associations from the store
|
66
|
+
# Not called during normal library operation, this method is for store
|
67
|
+
# admins to keep their storage from filling up with expired data
|
68
|
+
def cleanup
|
69
|
+
cleanup_nonces
|
70
|
+
cleanup_associations
|
71
|
+
end
|
72
|
+
|
73
|
+
# Remove expired associations from the store
|
74
|
+
# Not called during normal library operation, this method is for store
|
75
|
+
# admins to keep their storage from filling up with expired data
|
76
|
+
def cleanup_associations
|
77
|
+
oas = OpenidAssociation.all.collect do |oa|
|
78
|
+
oa.id if build_association(oa).expires_in == 0
|
79
|
+
end
|
80
|
+
OpenidAssociation.delete oas.compact
|
81
|
+
end
|
82
|
+
|
83
|
+
# Remove expired nonces from the store
|
84
|
+
# Discards any nonce that is old enough that it wouldn't pass use_nonce
|
85
|
+
# Not called during normal library operation, this method is for store
|
86
|
+
# admins to keep their storage from filling up with expired data
|
87
|
+
def cleanup_nonces
|
88
|
+
now = Time.now.to_i
|
89
|
+
nonces = OpenidNonce.all
|
90
|
+
ids = nonces.collect { |n| n.id if (n.timestamp - now).abs > Nonce.skew }
|
91
|
+
OpenidNonce.delete ids.compact
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def targetize(server_url)
|
97
|
+
OpenSSL::Digest::MD5.hexdigest(server_url)
|
98
|
+
end
|
99
|
+
|
100
|
+
def build_association(open_id_association)
|
101
|
+
OpenID::Association.new(
|
102
|
+
open_id_association.handle,
|
103
|
+
open_id_association.secret,
|
104
|
+
open_id_association.issued_at,
|
105
|
+
open_id_association.lifetime,
|
106
|
+
open_id_association.assoc_type
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_nonce(server_url, timestamp, salt)
|
111
|
+
OpenidNonce.create!(
|
112
|
+
:target => targetize(server_url),
|
113
|
+
:server_url => server_url,
|
114
|
+
:timestamp => timestamp
|
115
|
+
)
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rails/engine'
|
2
|
+
require 'openid/store/active_record'
|
3
|
+
|
4
|
+
module OpenidActiveRecordStore
|
5
|
+
class Engine < Rails::Engine
|
6
|
+
config.eager_load_paths << File.expand_path("../../app/models", __FILE__)
|
7
|
+
end
|
8
|
+
class Railtie < Rails::Railtie
|
9
|
+
rake_tasks do
|
10
|
+
namespace :openid_active_record_store do
|
11
|
+
namespace :install do
|
12
|
+
|
13
|
+
files = File.expand_path("../../db/migrate/*.rb", __FILE__)
|
14
|
+
sources = FileList[files]
|
15
|
+
targets = sources.map do |source|
|
16
|
+
ts = Time.now.to_f.to_s.sub('.', '')
|
17
|
+
"db/migrate/#{ts}_#{File.basename(source)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "install migrations"
|
21
|
+
task :migrations => targets
|
22
|
+
|
23
|
+
sources.zip(targets).each do |source, target|
|
24
|
+
file target => source do
|
25
|
+
cp source, target
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end unless Gem::Version.new(Rails.version) >= Gem::Version.new('3.1.0')
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'openid/store/nonce'
|
3
|
+
|
4
|
+
class OpenidStoreActiveRecordTest < ActiveSupport::TestCase
|
5
|
+
|
6
|
+
# ============================================================================
|
7
|
+
# TESTING SCENARIO
|
8
|
+
# ============================================================================
|
9
|
+
|
10
|
+
setup :prepare_scenario, :clean_tables
|
11
|
+
teardown :destroy_scenario
|
12
|
+
|
13
|
+
def prepare_scenario
|
14
|
+
@store = OpenID::Store::ActiveRecord.new
|
15
|
+
@@allowed_nonce = '0123456789abcdefghijklmnopqrst' +
|
16
|
+
'uvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
17
|
+
@@allowed_handle = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ' +
|
18
|
+
'RSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
|
19
|
+
end
|
20
|
+
|
21
|
+
def clean_tables
|
22
|
+
# super duper make sure talbes are empty
|
23
|
+
OpenidAssociation.all.each { |ao| ao.destroy }
|
24
|
+
OpenidNonce.all.each { |nonce| nonce.destroy }
|
25
|
+
end
|
26
|
+
|
27
|
+
def destroy_scenario
|
28
|
+
@@allowed_handle = @@allowed_nonce = @store = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# ============================================================================
|
32
|
+
# TESTS BELOW BROUGHT FROM THE ORIGINAL 'ruby-openid' (store) test suite
|
33
|
+
# these methods test the association interactivity with a store object
|
34
|
+
# ============================================================================
|
35
|
+
|
36
|
+
def _gen_secret(n, chars=nil)
|
37
|
+
OpenID::CryptUtil.random_string(n, chars)
|
38
|
+
end
|
39
|
+
|
40
|
+
def _gen_handle(n)
|
41
|
+
OpenID::CryptUtil.random_string(n, @@allowed_handle)
|
42
|
+
end
|
43
|
+
|
44
|
+
def _gen_assoc(issued_at, lifetime=600)
|
45
|
+
secret = _gen_secret(20)
|
46
|
+
handle = _gen_handle(128)
|
47
|
+
OpenID::Association.new(handle, secret, Time.now + issued_at, lifetime,
|
48
|
+
'HMAC-SHA1')
|
49
|
+
end
|
50
|
+
|
51
|
+
def _check_retrieve(url, handle=nil, expected=nil)
|
52
|
+
ret_assoc = @store.get_association(url, handle)
|
53
|
+
|
54
|
+
if expected.nil?
|
55
|
+
assert_nil(ret_assoc)
|
56
|
+
else
|
57
|
+
%w[assoc_type handle issued lifetime secret].each do |prop|
|
58
|
+
ex, actual = expected.send(prop), ret_assoc.send(prop)
|
59
|
+
if ex.kind_of?(Time)
|
60
|
+
ex, actual = ex.to_i, actual.to_i
|
61
|
+
end
|
62
|
+
assert_equal ex, actual, "#{prop} doesn't match"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def _check_remove(url, handle, expected)
|
68
|
+
present = @store.remove_association(url, handle)
|
69
|
+
assert_equal(expected, present)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_store
|
73
|
+
server_url = "http://www.myopenid.com/openid"
|
74
|
+
assoc = _gen_assoc(issued_at=0)
|
75
|
+
|
76
|
+
# Make sure that a missing association returns no result
|
77
|
+
_check_retrieve(server_url)
|
78
|
+
|
79
|
+
# Check that after storage, getting returns the same result
|
80
|
+
@store.store_association(server_url, assoc)
|
81
|
+
_check_retrieve(server_url, nil, assoc)
|
82
|
+
|
83
|
+
# more than once
|
84
|
+
_check_retrieve(server_url, nil, assoc)
|
85
|
+
|
86
|
+
# Storing more than once has no ill effect
|
87
|
+
@store.store_association(server_url, assoc)
|
88
|
+
_check_retrieve(server_url, nil, assoc)
|
89
|
+
|
90
|
+
# Removing an association that does not exist returns not present
|
91
|
+
_check_remove(server_url, assoc.handle + 'x', false)
|
92
|
+
|
93
|
+
# Removing an association that does not exist returns not present
|
94
|
+
_check_remove(server_url + 'x', assoc.handle, false)
|
95
|
+
|
96
|
+
# Removing an association that is present returns present
|
97
|
+
_check_remove(server_url, assoc.handle, true)
|
98
|
+
|
99
|
+
# but not present on subsequent calls
|
100
|
+
_check_remove(server_url, assoc.handle, false)
|
101
|
+
|
102
|
+
# Put assoc back in the store
|
103
|
+
@store.store_association(server_url, assoc)
|
104
|
+
|
105
|
+
# More recent and expires after assoc
|
106
|
+
assoc2 = _gen_assoc(issued_at=1)
|
107
|
+
@store.store_association(server_url, assoc2)
|
108
|
+
|
109
|
+
# After storing an association with a different handle, but the
|
110
|
+
# same server_url, the handle with the later expiration is returned.
|
111
|
+
_check_retrieve(server_url, nil, assoc2)
|
112
|
+
|
113
|
+
# We can still retrieve the older association
|
114
|
+
_check_retrieve(server_url, assoc.handle, assoc)
|
115
|
+
|
116
|
+
# Plus we can retrieve the association with the later expiration
|
117
|
+
# explicitly
|
118
|
+
_check_retrieve(server_url, assoc2.handle, assoc2)
|
119
|
+
|
120
|
+
# More recent, and expires earlier than assoc2 or assoc. Make sure
|
121
|
+
# that we're picking the one with the latest issued date and not
|
122
|
+
# taking into account the expiration.
|
123
|
+
assoc3 = _gen_assoc(issued_at=2, lifetime=100)
|
124
|
+
@store.store_association(server_url, assoc3)
|
125
|
+
|
126
|
+
_check_retrieve(server_url, nil, assoc3)
|
127
|
+
_check_retrieve(server_url, assoc.handle, assoc)
|
128
|
+
_check_retrieve(server_url, assoc2.handle, assoc2)
|
129
|
+
_check_retrieve(server_url, assoc3.handle, assoc3)
|
130
|
+
|
131
|
+
_check_remove(server_url, assoc2.handle, true)
|
132
|
+
|
133
|
+
_check_retrieve(server_url, nil, assoc3)
|
134
|
+
_check_retrieve(server_url, assoc.handle, assoc)
|
135
|
+
_check_retrieve(server_url, assoc2.handle, nil)
|
136
|
+
_check_retrieve(server_url, assoc3.handle, assoc3)
|
137
|
+
|
138
|
+
_check_remove(server_url, assoc2.handle, false)
|
139
|
+
_check_remove(server_url, assoc3.handle, true)
|
140
|
+
|
141
|
+
_check_retrieve(server_url, nil, assoc)
|
142
|
+
_check_retrieve(server_url, assoc.handle, assoc)
|
143
|
+
_check_retrieve(server_url, assoc2.handle, nil)
|
144
|
+
_check_retrieve(server_url, assoc3.handle, nil)
|
145
|
+
|
146
|
+
_check_remove(server_url, assoc2.handle, false)
|
147
|
+
_check_remove(server_url, assoc.handle, true)
|
148
|
+
_check_remove(server_url, assoc3.handle, false)
|
149
|
+
|
150
|
+
_check_retrieve(server_url, nil, nil)
|
151
|
+
_check_retrieve(server_url, assoc.handle, nil)
|
152
|
+
_check_retrieve(server_url, assoc2.handle, nil)
|
153
|
+
_check_retrieve(server_url, assoc3.handle, nil)
|
154
|
+
|
155
|
+
_check_remove(server_url, assoc2.handle, false)
|
156
|
+
_check_remove(server_url, assoc.handle, false)
|
157
|
+
_check_remove(server_url, assoc3.handle, false)
|
158
|
+
|
159
|
+
assocValid1 = _gen_assoc(-3600, 7200)
|
160
|
+
assocValid2 = _gen_assoc(-5)
|
161
|
+
assocExpired1 = _gen_assoc(-7200, 3600)
|
162
|
+
assocExpired2 = _gen_assoc(-7200, 3600)
|
163
|
+
|
164
|
+
@store.cleanup_associations
|
165
|
+
@store.store_association(server_url + '1', assocValid1)
|
166
|
+
@store.store_association(server_url + '1', assocExpired1)
|
167
|
+
@store.store_association(server_url + '2', assocExpired2)
|
168
|
+
@store.store_association(server_url + '3', assocValid2)
|
169
|
+
|
170
|
+
cleaned = @store.cleanup_associations()
|
171
|
+
assert_equal(2, cleaned, "cleaned up associations")
|
172
|
+
end
|
173
|
+
|
174
|
+
# ============================================================================
|
175
|
+
# am including open id here because the nonce module is not being mocked
|
176
|
+
# ============================================================================
|
177
|
+
include OpenID
|
178
|
+
|
179
|
+
# ============================================================================
|
180
|
+
# TESTS BELOW BROUGHT FROM THE ORIGINAL 'ruby-openid' (store) test suite
|
181
|
+
# these methods test the nonce interactivity with a store object
|
182
|
+
# ============================================================================
|
183
|
+
|
184
|
+
def _check_use_nonce(nonce, expected, server_url, msg='')
|
185
|
+
stamp, salt = Nonce::split_nonce(nonce)
|
186
|
+
actual = @store.use_nonce(server_url, stamp, salt)
|
187
|
+
assert_equal(expected, actual, msg)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_nonce
|
191
|
+
server_url = "http://www.myopenid.com/openid"
|
192
|
+
[server_url, ''].each{|url|
|
193
|
+
nonce1 = Nonce::mk_nonce
|
194
|
+
|
195
|
+
_check_use_nonce(nonce1, true, url, "#{url}: nonce allowed by default")
|
196
|
+
_check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed twice")
|
197
|
+
_check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed third time")
|
198
|
+
|
199
|
+
# old nonces shouldn't pass
|
200
|
+
old_nonce = Nonce::mk_nonce(3600)
|
201
|
+
_check_use_nonce(old_nonce, false, url, "Old nonce #{old_nonce.inspect} passed")
|
202
|
+
|
203
|
+
}
|
204
|
+
|
205
|
+
now = Time.now.to_i
|
206
|
+
old_nonce1 = Nonce::mk_nonce(now - 20000)
|
207
|
+
old_nonce2 = Nonce::mk_nonce(now - 10000)
|
208
|
+
recent_nonce = Nonce::mk_nonce(now - 600)
|
209
|
+
|
210
|
+
orig_skew = Nonce.skew
|
211
|
+
Nonce.skew = 0
|
212
|
+
count = @store.cleanup_nonces
|
213
|
+
Nonce.skew = 1000000
|
214
|
+
ts, salt = Nonce::split_nonce(old_nonce1)
|
215
|
+
assert(@store.use_nonce(server_url, ts, salt), "oldnonce1")
|
216
|
+
ts, salt = Nonce::split_nonce(old_nonce2)
|
217
|
+
assert(@store.use_nonce(server_url, ts, salt), "oldnonce2")
|
218
|
+
ts, salt = Nonce::split_nonce(recent_nonce)
|
219
|
+
assert(@store.use_nonce(server_url, ts, salt), "recent_nonce")
|
220
|
+
|
221
|
+
|
222
|
+
Nonce.skew = 1000
|
223
|
+
cleaned = @store.cleanup_nonces
|
224
|
+
assert_equal(2, cleaned, "Cleaned #{cleaned} nonces")
|
225
|
+
|
226
|
+
Nonce.skew = 100000
|
227
|
+
ts, salt = Nonce::split_nonce(old_nonce1)
|
228
|
+
assert(@store.use_nonce(server_url, ts, salt), "oldnonce1 after cleanup")
|
229
|
+
ts, salt = Nonce::split_nonce(old_nonce2)
|
230
|
+
assert(@store.use_nonce(server_url, ts, salt), "oldnonce2 after cleanup")
|
231
|
+
ts, salt = Nonce::split_nonce(recent_nonce)
|
232
|
+
assert(!@store.use_nonce(server_url, ts, salt), "recent_nonce after cleanup")
|
233
|
+
|
234
|
+
Nonce.skew = orig_skew
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'openid_active_record_store'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
db = {
|
6
|
+
:adapter => :mysql2,
|
7
|
+
:database => 'openid_active_record_store'
|
8
|
+
}
|
9
|
+
|
10
|
+
# XXX yes, there are better ways. patches please!
|
11
|
+
|
12
|
+
system "echo 'drop database #{db[:database]};' | mysql5 -uroot" rescue nil
|
13
|
+
system "echo 'create database #{db[:database]};' | mysql5 -uroot"
|
14
|
+
|
15
|
+
ActiveRecord::Base.establish_connection db
|
16
|
+
|
17
|
+
Dir['app/models/*.rb'].each do |model|
|
18
|
+
require File.expand_path(model)
|
19
|
+
end
|
20
|
+
|
21
|
+
Dir['db/migrations/*.rb'].each do |migration|
|
22
|
+
require migration
|
23
|
+
Object.const_get(File.basename(migration, '.rb').camelize).up
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: openid_active_record_store
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- James Tucker
|
14
|
+
- Kazuyoshi Tlacaelel
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-05-24 00:00:00 -07:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: rails
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 5
|
31
|
+
segments:
|
32
|
+
- 3
|
33
|
+
version: "3"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
description: An ActiveRecord store for OpenID, forked from its original author for rails 3 support
|
37
|
+
email: info@wildfireapp.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- README.rdoc
|
46
|
+
- Rakefile
|
47
|
+
- app/models/openid_abstract.rb
|
48
|
+
- app/models/openid_association.rb
|
49
|
+
- app/models/openid_nonce.rb
|
50
|
+
- db/migrate/create_openid_associations.rb
|
51
|
+
- db/migrate/create_openid_nonces.rb
|
52
|
+
- lib/openid/store/active_record.rb
|
53
|
+
- lib/openid_active_record_store.rb
|
54
|
+
- test/openid_store_active_record_test.rb
|
55
|
+
- test/test_helper.rb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://github.com/wildfireapp/openid_active_record_store
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 3
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.5.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: An ActiveRecord store for OpenID
|
90
|
+
test_files: []
|
91
|
+
|