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 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
+