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 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,11 @@
1
+ begin
2
+ require ::File.expand_path('.bundle/environment', __FILE__)
3
+ rescue LoadError
4
+ require "rubygems"
5
+ require "bundler"
6
+ Bundler.setup
7
+ end
8
+
9
+ Bundler.require(:default, :rake)
10
+
11
+ Dir["tasks/*.rake"].sort.each { |file| load file }
@@ -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
@@ -0,0 +1,8 @@
1
+ module OpenIDStoreMongoid
2
+ class Nonce
3
+ include ::Mongoid::Document
4
+ field :salt
5
+ field :server_url
6
+ field :timestamp, :type => Integer
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module OpenIDStoreMongoid
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,4 @@
1
+ require 'mongoid'
2
+ require 'openid_store_mongoid/association'
3
+ require 'openid_store_mongoid/nonce'
4
+ require 'openid/store/mongoid'
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
+