openid_store_mongoid 0.0.1
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.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
|
+
|