openid_store_mongoid 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +30 -0
- data/Rakefile +11 -0
- data/lib/openid/store/mongoid.rb +66 -0
- data/lib/openid_store_mongoid/association.rb +15 -0
- data/lib/openid_store_mongoid/nonce.rb +8 -0
- data/lib/openid_store_mongoid/version.rb +3 -0
- data/lib/openid_store_mongoid.rb +4 -0
- data/tasks/gem.rake +43 -0
- data/test/test_openid_store_mongoid.rb +240 -0
- metadata +151 -0
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
## openid_mongoid_store
|
2
|
+
|
3
|
+
Storing your OpenIDs in your Mongos.
|
4
|
+
|
5
|
+
### usage
|
6
|
+
|
7
|
+
database = Mongo::Connection.new.db('openid_store_mongoid')
|
8
|
+
store = OpenID::Store::Mongoid.new(database)
|
9
|
+
server = OpenID::Server::Server.new(store, ...)
|
10
|
+
|
11
|
+
### license (MIT)
|
12
|
+
|
13
|
+
Copyright (c) 2010 Dylan Egan
|
14
|
+
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
17
|
+
in the Software without restriction, including without limitation the rights
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
20
|
+
furnished to do so, subject to the following conditions:
|
21
|
+
|
22
|
+
The above copyright notice and this permission notice shall be included in
|
23
|
+
all copies or substantial portions of the Software.
|
24
|
+
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
30
|
+
OUT OF OR IN CON
|
data/Rakefile
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'openid/store/interface'
|
2
|
+
|
3
|
+
module OpenID
|
4
|
+
module Store
|
5
|
+
class Mongoid < OpenID::Store::Interface
|
6
|
+
def initialize(connection)
|
7
|
+
::Mongoid.database = connection
|
8
|
+
end
|
9
|
+
|
10
|
+
def store_association(server_url, assoc)
|
11
|
+
remove_association(server_url, assoc.handle)
|
12
|
+
OpenIDStoreMongoid::Association.create!(:server_url => server_url,
|
13
|
+
:handle => assoc.handle,
|
14
|
+
:secret => BSON::Binary.new(assoc.secret),
|
15
|
+
:issued => assoc.issued,
|
16
|
+
:lifetime => assoc.lifetime,
|
17
|
+
:assoc_type => assoc.assoc_type)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_association(server_url, handle=nil)
|
21
|
+
assocs = if handle.blank?
|
22
|
+
OpenIDStoreMongoid::Association.all(:conditions => { :server_url => server_url })
|
23
|
+
else
|
24
|
+
OpenIDStoreMongoid::Association.all(:conditions => { :server_url => server_url, :handle => handle })
|
25
|
+
end
|
26
|
+
|
27
|
+
assocs.to_a.reverse.each do |assoc|
|
28
|
+
a = assoc.from_record
|
29
|
+
if a.expires_in == 0
|
30
|
+
assoc.destroy
|
31
|
+
else
|
32
|
+
return a
|
33
|
+
end
|
34
|
+
end if assocs.any?
|
35
|
+
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove_association(server_url, handle)
|
40
|
+
OpenIDStoreMongoid::Association.destroy_all(:conditions => { :server_url => server_url, :handle => handle }) > 0 ? true : false
|
41
|
+
end
|
42
|
+
|
43
|
+
def use_nonce(server_url, timestamp, salt)
|
44
|
+
return false if OpenIDStoreMongoid::Nonce.first(:conditions => { :server_url => server_url, :timestamp => timestamp, :salt => salt }) or (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew
|
45
|
+
OpenIDStoreMongoid::Nonce.create!(:server_url => server_url, :timestamp => timestamp, :salt => salt)
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
|
49
|
+
def cleanup_nonces
|
50
|
+
now = Time.now.to_i
|
51
|
+
OpenIDStoreMongoid::Nonce.destroy_all(:conditions => { :timestamp.gt => (now + OpenID::Nonce.skew), :timestamp.lt => (now - OpenID::Nonce.skew) })
|
52
|
+
end
|
53
|
+
|
54
|
+
def cleanup_associations
|
55
|
+
count = 0
|
56
|
+
OpenIDStoreMongoid::Association.all(:conditions => { :issued.gt => 0 }).each do |association|
|
57
|
+
if association.lifetime + association.issued > Time.now.to_i
|
58
|
+
association.destroy
|
59
|
+
count += 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
count
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module OpenIDStoreMongoid
|
2
|
+
class Association
|
3
|
+
include ::Mongoid::Document
|
4
|
+
field :handle
|
5
|
+
field :secret, :type => Binary
|
6
|
+
field :issued, :type => Integer
|
7
|
+
field :lifetime, :type => Integer
|
8
|
+
field :assoc_type
|
9
|
+
field :server_url, :type => Binary
|
10
|
+
|
11
|
+
def from_record
|
12
|
+
OpenID::Association.new(handle, secret.to_s, issued, lifetime, assoc_type)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/tasks/gem.rake
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rubygems/package_task'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/openid_store_mongoid/version'
|
3
|
+
|
4
|
+
GEM_SPEC = Gem::Specification.new do |s|
|
5
|
+
s.name = "openid_store_mongoid"
|
6
|
+
s.version = OpenIDStoreMongoid::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
|
9
|
+
s.summary = 'Storing your OpenIDs in your Mongos.'
|
10
|
+
s.description = "Why does a squirrel swim on its back?\nTo keep its nuts dry"
|
11
|
+
|
12
|
+
s.required_ruby_version = ">= 1.8.6"
|
13
|
+
s.required_rubygems_version = ">= 1.3.5"
|
14
|
+
|
15
|
+
# dependencies
|
16
|
+
s.add_dependency 'rake', '>= 0.8.3', '< 0.9'
|
17
|
+
bundle = Bundler::Definition.from_gemfile("Gemfile")
|
18
|
+
bundle.dependencies.select { |d| !d.groups.include?(:development) and !d.groups.include?(:rake) }.
|
19
|
+
each { |d| s.add_dependency(d.name, d.requirement.to_s) }
|
20
|
+
|
21
|
+
bundle.dependencies.select { |d| d.groups.include?(:development) }.
|
22
|
+
each { |d| s.add_development_dependency(d.name, d.requirement.to_s) }
|
23
|
+
|
24
|
+
s.files = FileList["lib/**/*.rb", "test/**/*.rb", "tasks/**/*.rake", "Rakefile", "README.md"]
|
25
|
+
|
26
|
+
s.bindir = 'bin'
|
27
|
+
s.executables = []
|
28
|
+
|
29
|
+
s.require_path = 'lib'
|
30
|
+
|
31
|
+
s.extra_rdoc_files = %w(README.md)
|
32
|
+
|
33
|
+
s.homepage = 'http://github.com/abcde/openid_store_mongoid'
|
34
|
+
s.licenses = ['MIT']
|
35
|
+
|
36
|
+
s.author = 'Dylan Egan'
|
37
|
+
s.email = 'dylanegan@gmail.com'
|
38
|
+
end
|
39
|
+
|
40
|
+
gem_package = Gem::PackageTask.new(GEM_SPEC) do |pkg|
|
41
|
+
pkg.need_tar = false
|
42
|
+
pkg.need_zip = false
|
43
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
begin
|
2
|
+
# Require the preresolved locked set of gems.
|
3
|
+
require ::File.expand_path('../.bundle/environment', __FILE__)
|
4
|
+
rescue LoadError
|
5
|
+
# Fallback on doing the resolve at runtime.
|
6
|
+
require "rubygems"
|
7
|
+
require "bundler"
|
8
|
+
Bundler.setup
|
9
|
+
Bundler.require(:default, :test)
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'test/unit'
|
13
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
14
|
+
require 'openid_store_mongoid'
|
15
|
+
require 'openid/util'
|
16
|
+
require 'openid/store/nonce'
|
17
|
+
require 'openid/association'
|
18
|
+
|
19
|
+
module OpenID
|
20
|
+
module Store
|
21
|
+
module StoreTestCase
|
22
|
+
@@allowed_handle = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
|
23
|
+
@@allowed_nonce = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
24
|
+
|
25
|
+
def _gen_nonce
|
26
|
+
OpenID::CryptUtil.random_string(8, @@allowed_nonce)
|
27
|
+
end
|
28
|
+
|
29
|
+
def _gen_handle(n)
|
30
|
+
OpenID::CryptUtil.random_string(n, @@allowed_handle)
|
31
|
+
end
|
32
|
+
|
33
|
+
def _gen_secret(n, chars=nil)
|
34
|
+
OpenID::CryptUtil.random_string(n, chars)
|
35
|
+
end
|
36
|
+
|
37
|
+
def _gen_assoc(issued, lifetime=600)
|
38
|
+
secret = _gen_secret(20)
|
39
|
+
handle = _gen_handle(128)
|
40
|
+
OpenID::Association.new(handle, secret, Time.now + issued, lifetime,
|
41
|
+
'HMAC-SHA1')
|
42
|
+
end
|
43
|
+
|
44
|
+
def _check_retrieve(url, handle=nil, expected=nil)
|
45
|
+
ret_assoc = @store.get_association(url, handle)
|
46
|
+
|
47
|
+
if expected.nil?
|
48
|
+
assert_nil(ret_assoc)
|
49
|
+
else
|
50
|
+
assert_equal(expected, ret_assoc)
|
51
|
+
assert_equal(expected.handle, ret_assoc.handle)
|
52
|
+
assert_equal(expected.secret, ret_assoc.secret)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def _check_remove(url, handle, expected)
|
57
|
+
present = @store.remove_association(url, handle)
|
58
|
+
assert_equal(expected, present)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_store
|
62
|
+
assoc = _gen_assoc(issued=0)
|
63
|
+
|
64
|
+
# Make sure that a missing association returns no result
|
65
|
+
_check_retrieve(server_url)
|
66
|
+
|
67
|
+
# Check that after storage, getting returns the same result
|
68
|
+
@store.store_association(server_url, assoc)
|
69
|
+
_check_retrieve(server_url, nil, assoc)
|
70
|
+
|
71
|
+
# more than once
|
72
|
+
_check_retrieve(server_url, nil, assoc)
|
73
|
+
|
74
|
+
# Storing more than once has no ill effect
|
75
|
+
@store.store_association(server_url, assoc)
|
76
|
+
_check_retrieve(server_url, nil, assoc)
|
77
|
+
|
78
|
+
# Removing an association that does not exist returns not present
|
79
|
+
_check_remove(server_url, assoc.handle + 'x', false)
|
80
|
+
|
81
|
+
# Removing an association that does not exist returns not present
|
82
|
+
_check_remove(server_url + 'x', assoc.handle, false)
|
83
|
+
|
84
|
+
# Removing an association that is present returns present
|
85
|
+
_check_remove(server_url, assoc.handle, true)
|
86
|
+
|
87
|
+
# but not present on subsequent calls
|
88
|
+
_check_remove(server_url, assoc.handle, false)
|
89
|
+
|
90
|
+
# Put assoc back in the store
|
91
|
+
@store.store_association(server_url, assoc)
|
92
|
+
|
93
|
+
# More recent and expires after assoc
|
94
|
+
assoc2 = _gen_assoc(issued=1)
|
95
|
+
@store.store_association(server_url, assoc2)
|
96
|
+
|
97
|
+
# After storing an association with a different handle, but the
|
98
|
+
# same server_url, the handle with the later expiration is returned.
|
99
|
+
_check_retrieve(server_url, nil, assoc2)
|
100
|
+
|
101
|
+
# We can still retrieve the older association
|
102
|
+
_check_retrieve(server_url, assoc.handle, assoc)
|
103
|
+
|
104
|
+
# Plus we can retrieve the association with the later expiration
|
105
|
+
# explicitly
|
106
|
+
_check_retrieve(server_url, assoc2.handle, assoc2)
|
107
|
+
|
108
|
+
# More recent, and expires earlier than assoc2 or assoc. Make sure
|
109
|
+
# that we're picking the one with the latest issued date and not
|
110
|
+
# taking into account the expiration.
|
111
|
+
assoc3 = _gen_assoc(issued=2, lifetime=100)
|
112
|
+
@store.store_association(server_url, assoc3)
|
113
|
+
|
114
|
+
_check_retrieve(server_url, nil, assoc3)
|
115
|
+
_check_retrieve(server_url, assoc.handle, assoc)
|
116
|
+
_check_retrieve(server_url, assoc2.handle, assoc2)
|
117
|
+
_check_retrieve(server_url, assoc3.handle, assoc3)
|
118
|
+
|
119
|
+
_check_remove(server_url, assoc2.handle, true)
|
120
|
+
|
121
|
+
_check_retrieve(server_url, nil, assoc3)
|
122
|
+
_check_retrieve(server_url, assoc.handle, assoc)
|
123
|
+
_check_retrieve(server_url, assoc2.handle, nil)
|
124
|
+
_check_retrieve(server_url, assoc3.handle, assoc3)
|
125
|
+
|
126
|
+
_check_remove(server_url, assoc2.handle, false)
|
127
|
+
_check_remove(server_url, assoc3.handle, true)
|
128
|
+
|
129
|
+
ret_assoc = @store.get_association(server_url, nil)
|
130
|
+
unexpected = [assoc2.handle, assoc3.handle]
|
131
|
+
assert(ret_assoc.nil? || !unexpected.member?(ret_assoc.handle),
|
132
|
+
ret_assoc)
|
133
|
+
|
134
|
+
_check_retrieve(server_url, assoc.handle, assoc)
|
135
|
+
_check_retrieve(server_url, assoc2.handle, nil)
|
136
|
+
_check_retrieve(server_url, assoc3.handle, nil)
|
137
|
+
|
138
|
+
_check_remove(server_url, assoc2.handle, false)
|
139
|
+
_check_remove(server_url, assoc.handle, true)
|
140
|
+
_check_remove(server_url, assoc3.handle, false)
|
141
|
+
|
142
|
+
_check_retrieve(server_url, nil, nil)
|
143
|
+
_check_retrieve(server_url, assoc.handle, nil)
|
144
|
+
_check_retrieve(server_url, assoc2.handle, nil)
|
145
|
+
_check_retrieve(server_url, assoc3.handle, nil)
|
146
|
+
|
147
|
+
_check_remove(server_url, assoc2.handle, false)
|
148
|
+
_check_remove(server_url, assoc.handle, false)
|
149
|
+
_check_remove(server_url, assoc3.handle, false)
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_assoc_cleanup
|
153
|
+
assocValid1 = _gen_assoc(-3600, 7200)
|
154
|
+
assocValid2 = _gen_assoc(-5)
|
155
|
+
assocExpired1 = _gen_assoc(-7200, 3600)
|
156
|
+
assocExpired2 = _gen_assoc(-7200, 3600)
|
157
|
+
|
158
|
+
@store.cleanup_associations
|
159
|
+
@store.store_association(server_url + '1', assocValid1)
|
160
|
+
@store.store_association(server_url + '1', assocExpired1)
|
161
|
+
@store.store_association(server_url + '2', assocExpired2)
|
162
|
+
@store.store_association(server_url + '3', assocValid2)
|
163
|
+
|
164
|
+
cleaned = @store.cleanup_associations()
|
165
|
+
assert_equal(2, cleaned, "cleaned up associations")
|
166
|
+
end
|
167
|
+
|
168
|
+
def _check_use_nonce(nonce, expected, server_url, msg='')
|
169
|
+
stamp, salt = Nonce::split_nonce(nonce)
|
170
|
+
actual = @store.use_nonce(server_url, stamp, salt)
|
171
|
+
assert_equal(expected, actual, msg)
|
172
|
+
end
|
173
|
+
|
174
|
+
def server_url
|
175
|
+
"http://www.myopenid.com/openid"
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_nonce
|
179
|
+
[server_url, ''].each{|url|
|
180
|
+
nonce1 = Nonce::mk_nonce
|
181
|
+
|
182
|
+
_check_use_nonce(nonce1, true, url, "#{url}: nonce allowed by default")
|
183
|
+
_check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed twice")
|
184
|
+
_check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed third time")
|
185
|
+
|
186
|
+
# old nonces shouldn't pass
|
187
|
+
old_nonce = Nonce::mk_nonce(3600)
|
188
|
+
_check_use_nonce(old_nonce, false, url, "Old nonce #{old_nonce.inspect} passed")
|
189
|
+
|
190
|
+
}
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_nonce_cleanup
|
194
|
+
now = Time.now.to_i
|
195
|
+
old_nonce1 = Nonce::mk_nonce(now - 20000)
|
196
|
+
old_nonce2 = Nonce::mk_nonce(now - 10000)
|
197
|
+
recent_nonce = Nonce::mk_nonce(now - 600)
|
198
|
+
|
199
|
+
orig_skew = Nonce.skew
|
200
|
+
Nonce.skew = 0
|
201
|
+
count = @store.cleanup_nonces
|
202
|
+
Nonce.skew = 1000000
|
203
|
+
ts, salt = Nonce::split_nonce(old_nonce1)
|
204
|
+
assert(@store.use_nonce(server_url, ts, salt), "oldnonce1")
|
205
|
+
ts, salt = Nonce::split_nonce(old_nonce2)
|
206
|
+
assert(@store.use_nonce(server_url, ts, salt), "oldnonce2")
|
207
|
+
ts, salt = Nonce::split_nonce(recent_nonce)
|
208
|
+
assert(@store.use_nonce(server_url, ts, salt), "recent_nonce")
|
209
|
+
|
210
|
+
Nonce.skew = 1000
|
211
|
+
cleaned = @store.cleanup_nonces
|
212
|
+
assert_equal(2, cleaned, "Cleaned #{cleaned} nonces")
|
213
|
+
|
214
|
+
Nonce.skew = 100000
|
215
|
+
ts, salt = Nonce::split_nonce(old_nonce1)
|
216
|
+
assert(@store.use_nonce(server_url, ts, salt), "oldnonce1 after cleanup")
|
217
|
+
ts, salt = Nonce::split_nonce(old_nonce2)
|
218
|
+
assert(@store.use_nonce(server_url, ts, salt), "oldnonce2 after cleanup")
|
219
|
+
ts, salt = Nonce::split_nonce(recent_nonce)
|
220
|
+
assert(!@store.use_nonce(server_url, ts, salt), "recent_nonce after cleanup")
|
221
|
+
|
222
|
+
Nonce.skew = orig_skew
|
223
|
+
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
class MongoStoreTestCase < Test::Unit::TestCase
|
228
|
+
include StoreTestCase
|
229
|
+
|
230
|
+
def setup
|
231
|
+
@store = Mongoid.new(Mongo::Connection.new.db('openid_store_mongoid_test'))
|
232
|
+
end
|
233
|
+
|
234
|
+
def teardown
|
235
|
+
OpenIDStoreMongoid::Association.destroy_all
|
236
|
+
OpenIDStoreMongoid::Nonce.destroy_all
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: openid_store_mongoid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dylan Egan
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-06-05 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
name: rake
|
25
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 57
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
- 8
|
34
|
+
- 3
|
35
|
+
version: 0.8.3
|
36
|
+
- - <
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
hash: 25
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
- 9
|
42
|
+
version: "0.9"
|
43
|
+
requirement: *id001
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
name: ruby-openid
|
48
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
hash: 5
|
54
|
+
segments:
|
55
|
+
- 2
|
56
|
+
- 1
|
57
|
+
- 7
|
58
|
+
version: 2.1.7
|
59
|
+
requirement: *id002
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
name: bson_ext
|
64
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
hash: 21
|
70
|
+
segments:
|
71
|
+
- 1
|
72
|
+
- 0
|
73
|
+
- 1
|
74
|
+
version: 1.0.1
|
75
|
+
requirement: *id003
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
name: mongoid
|
80
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 51
|
86
|
+
segments:
|
87
|
+
- 1
|
88
|
+
- 9
|
89
|
+
- 0
|
90
|
+
version: 1.9.0
|
91
|
+
requirement: *id004
|
92
|
+
description: |-
|
93
|
+
Why does a squirrel swim on its back?
|
94
|
+
To keep its nuts dry
|
95
|
+
email: dylanegan@gmail.com
|
96
|
+
executables: []
|
97
|
+
|
98
|
+
extensions: []
|
99
|
+
|
100
|
+
extra_rdoc_files:
|
101
|
+
- README.md
|
102
|
+
files:
|
103
|
+
- lib/openid/store/mongoid.rb
|
104
|
+
- lib/openid_store_mongoid/association.rb
|
105
|
+
- lib/openid_store_mongoid/nonce.rb
|
106
|
+
- lib/openid_store_mongoid/version.rb
|
107
|
+
- lib/openid_store_mongoid.rb
|
108
|
+
- test/test_openid_store_mongoid.rb
|
109
|
+
- tasks/gem.rake
|
110
|
+
- Rakefile
|
111
|
+
- README.md
|
112
|
+
has_rdoc: true
|
113
|
+
homepage: http://github.com/abcde/openid_store_mongoid
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
hash: 59
|
127
|
+
segments:
|
128
|
+
- 1
|
129
|
+
- 8
|
130
|
+
- 6
|
131
|
+
version: 1.8.6
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
hash: 17
|
138
|
+
segments:
|
139
|
+
- 1
|
140
|
+
- 3
|
141
|
+
- 5
|
142
|
+
version: 1.3.5
|
143
|
+
requirements: []
|
144
|
+
|
145
|
+
rubyforge_project:
|
146
|
+
rubygems_version: 1.3.7
|
147
|
+
signing_key:
|
148
|
+
specification_version: 3
|
149
|
+
summary: Storing your OpenIDs in your Mongos.
|
150
|
+
test_files: []
|
151
|
+
|