openid-store-redis 0.1.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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - jruby-19mode
7
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in openid-store-redis.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Rally Software Development Corp
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # OpenID::Store::Redis [![Build Status](https://travis-ci.org/RallySoftware/openid-store-redis.png)](https://travis-ci.org/RallySoftware/openid-store-redis)
2
+
3
+ A Redis storage backend for ruby-openid
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'openid-store-redis'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install openid-store-redis
18
+
19
+ ## Usage
20
+
21
+ Set up OpenID consumer (or provider) using Redis store
22
+
23
+ ```ruby
24
+ redis = Redis.new
25
+ store = OpenID::Store::Redis.new(redis)
26
+ @consumer = OpenID::Consumer.new(session, store)
27
+ ```
28
+
29
+ If you're using Omniauth
30
+
31
+ ```ruby
32
+ use OmniAuth::Builder do
33
+ provider :open_id, :store => OpenID::Store::Redis.new(Redis.new)
34
+ end
35
+ ```
36
+
37
+ Redis store defaults to ```Redis.current``` when Redis client is not given as
38
+ argument to store.
39
+
40
+ ## Contributing
41
+
42
+ 1. Fork it
43
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
44
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
45
+ 4. Push to the branch (`git push origin my-new-feature`)
46
+ 5. Create new Pull Request
47
+
48
+ ## Copyright
49
+
50
+ © Rally Software Development Corp. Released under MIT license, see
51
+ [LICENSE](https://github.com/RallySoftware/openid-redis-store/blob/master/LICENSE.txt)
52
+ for details.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = FileList['spec/**/*_spec.rb']
7
+ end
8
+
9
+ task :default => :spec
10
+
@@ -0,0 +1,5 @@
1
+ module OpenID
2
+ module Store
3
+ REDIS_VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,90 @@
1
+ require "openid/store/redis/version"
2
+ require "openid/store/interface"
3
+ require "redis"
4
+
5
+ module OpenID
6
+ module Store
7
+ class Redis < Interface
8
+ attr_reader :prefix
9
+ def initialize(client = ::Redis.current, prefix = "openid-store")
10
+ @redis = client
11
+ @prefix = prefix
12
+ end
13
+
14
+ # Store an Association in Redis
15
+ def store_association(server_url, association)
16
+ serialized = serialize(association)
17
+ [nil, association.handle].each do |handle|
18
+ key = assoc_key(server_url, handle)
19
+ @redis.setex(key, association.lifetime, serialized)
20
+ end
21
+ end
22
+
23
+ # Fetch and deserialize an Association object from Redis
24
+ def get_association(server_url, handle=nil)
25
+ if serialized = @redis.get(assoc_key(server_url, handle))
26
+ deserialize(serialized)
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
32
+ # Remove matching association from Redis
33
+ #
34
+ # return true when data is removed, otherwise false
35
+ def remove_association(url, handle)
36
+ deleted = @redis.del(assoc_key(url, handle))
37
+ assoc = get_association(url)
38
+ if assoc && assoc.handle == handle
39
+ deleted + @redis.del(assoc_key(url))
40
+ else
41
+ deleted
42
+ end > 0
43
+ end
44
+
45
+
46
+ # Use nonce and store that it has been used in Redis temporarily
47
+ #
48
+ # Returns true if nonce has not been used before and is still usable,
49
+ def use_nonce(server_url, timestamp, salt)
50
+ return false if (timestamp - Time.now.to_i).abs > Nonce.skew
51
+ ts = timestamp.to_s # base 10 seconds since epoch
52
+ nonce_key = prefix + ':n:' + server_url + ':' + ts + ':' + salt
53
+ if @redis.setnx(nonce_key, '')
54
+ @redis.expire(nonce_key, Nonce.skew + 5)
55
+ true
56
+ else
57
+ false
58
+ end
59
+ end
60
+
61
+ def cleanup_nonces
62
+ end
63
+
64
+ def cleanup
65
+ end
66
+
67
+ def cleanup_associations
68
+ end
69
+
70
+ private
71
+
72
+ def assoc_key(server_url, assoc_handle=nil)
73
+ key = prefix + ':a:' + server_url
74
+ if assoc_handle
75
+ key + ':' + assoc_handle
76
+ else
77
+ key
78
+ end
79
+ end
80
+
81
+ def serialize(assoc)
82
+ Marshal.dump(assoc)
83
+ end
84
+
85
+ def deserialize(assoc_str)
86
+ Marshal.load(assoc_str)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1 @@
1
+ require 'openid/store/redis'
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'openid/store/redis/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "openid-store-redis"
8
+ spec.version = OpenID::Store::REDIS_VERSION
9
+ spec.authors = ["Ville Lautanala"]
10
+ spec.email = ["lautis@gmail.com"]
11
+ spec.description = %q{Use Redis to store OpenID associations and nonces with ruby-openid}
12
+ spec.summary = %q{A Redis storage backend for ruby-openid}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "ruby-openid", ">= 2.1.7"
22
+ spec.add_runtime_dependency "redis", "~> 3.0"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec", "~> 2.13"
27
+ spec.add_development_dependency "mock_redis"
28
+ end
@@ -0,0 +1,129 @@
1
+ require 'spec_helper'
2
+ require 'securerandom'
3
+ require 'openid/association'
4
+ require 'openid/store/nonce'
5
+ Nonce = OpenID::Nonce
6
+
7
+ describe OpenID::Store::Redis do
8
+ let(:redis) { MockRedis.new }
9
+ let(:url) { 'https://example.com/' + SecureRandom.base64 }
10
+ let(:handle) { SecureRandom.base64 }
11
+
12
+ subject { OpenID::Store::Redis.new(redis) }
13
+
14
+ describe '#get_association' do
15
+ it 'returns nil when association does not exist' do
16
+ subject.get_association(url).should be_nil
17
+ end
18
+
19
+ it 'returns nil when association with handle does not exist' do
20
+ server_url = 'test/url'
21
+ handle = 'test/handle'
22
+ subject.get_association(url, handle).should be_nil
23
+ end
24
+
25
+ it 'returns association when exists' do
26
+ assn = association(0)
27
+ redis.set('openid-store:a:' + url, Marshal.dump(assn))
28
+ subject.get_association(url).handle.should eql assn.handle
29
+ subject.get_association(url).secret.should eql assn.secret
30
+ end
31
+
32
+ it 'returns association with handle' do
33
+ assoc = association(0)
34
+ redis.set('openid-store:a:' + url + ":" + handle, Marshal.dump(assoc))
35
+ subject.get_association(url, handle).handle.should eql assoc.handle
36
+ subject.get_association(url, handle).secret.should eql assoc.secret
37
+ end
38
+ end
39
+
40
+ describe '#store_association' do
41
+ it 'stores association to redis' do
42
+ assoc = association(0)
43
+ serialized = Marshal.dump(assoc)
44
+ subject.store_association(url, assoc)
45
+ redis.get('openid-store:a:' + url).should eql(serialized)
46
+ end
47
+
48
+ it 'stores with handle' do
49
+ assoc = association(0)
50
+ serialized = Marshal.dump(assoc)
51
+ subject.store_association(url, assoc)
52
+ redis.get('openid-store:a:' + url + ':' + assoc.handle).should eql(serialized)
53
+ end
54
+
55
+ it 'expires the association after lifetime' do
56
+ assoc = association(0)
57
+ subject.store_association(url, assoc)
58
+ ttl = redis.ttl('openid-store:a:' + url + ':' + assoc.handle)
59
+ ttl.should eql(assoc.lifetime)
60
+ end
61
+ end
62
+
63
+ describe '#remove_association' do
64
+ let(:assoc) { association(0) }
65
+ before :each do
66
+ redis.set('openid-store:a:' + url + ":" + assoc.handle, Marshal.dump(assoc))
67
+ redis.set('openid-store:a:' + url, Marshal.dump(assoc))
68
+ end
69
+
70
+ it 'removes association from redis' do
71
+ subject.remove_association(url, assoc.handle)
72
+ redis.get('openid-store:a:' + url + ":" + assoc.handle).should be_nil
73
+ redis.get('openid-store:a:' + url).should be_nil
74
+ end
75
+
76
+ it 'does not remove when handles do not match' do
77
+ subject.remove_association(url, assoc.handle + 'fail')
78
+ redis.get('openid-store:a:' + url + ":" + assoc.handle).should_not be_nil
79
+ end
80
+
81
+ it 'returns true when data is removed' do
82
+ subject.remove_association(url, assoc.handle).should be(true)
83
+ end
84
+
85
+ it 'returns false when data is not removed' do
86
+ subject.remove_association(url + 'fail', assoc.handle).should be(false)
87
+ end
88
+ end
89
+
90
+ describe '#use_nonce' do
91
+ it 'allows nonce to be used once' do
92
+ timestamp, salt = Nonce::split_nonce(Nonce::mk_nonce)
93
+ subject.use_nonce(url, timestamp.to_i, salt).should be_true
94
+ end
95
+
96
+ it 'does not allow multiple uses of nonce' do
97
+ timestamp, salt = Nonce::split_nonce(Nonce::mk_nonce)
98
+ subject.use_nonce(url, timestamp.to_i, salt)
99
+ subject.use_nonce(url, timestamp.to_i, salt).should be_false
100
+ end
101
+
102
+ it 'creates nonce if time is within skew' do
103
+ now = Time.now
104
+ timestamp = now.to_f + OpenID::Nonce.skew - 1
105
+ subject.use_nonce(url, timestamp, 'salt').should be_true
106
+ end
107
+
108
+ it 'returns false if time is beyond skew' do
109
+ now = Time.now
110
+ timestamp = now.to_f + OpenID::Nonce.skew + 1
111
+ subject.use_nonce(url, timestamp, 'salt').should be_false
112
+ end
113
+
114
+ it 'removes nonce from redis after skew timeout' do
115
+ ts, salt = Nonce::split_nonce(Nonce::mk_nonce)
116
+ subject.use_nonce(url, ts.to_i, salt)
117
+ ttl = redis.ttl('openid-store:n:' + url + ':' + ts.to_s + ':' + salt)
118
+ ttl.should eql(OpenID::Nonce.skew + 5)
119
+ end
120
+ end
121
+ end
122
+
123
+ def association(issued, lifetime=600)
124
+ OpenID::Association.new(SecureRandom.hex(128),
125
+ SecureRandom.base64(20),
126
+ Time.now + issued,
127
+ lifetime,
128
+ 'HMAC-SHA1')
129
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: UTF-8
2
+ require "openid-store-redis"
3
+ require "rspec"
4
+ require "mock_redis"
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: openid-store-redis
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Ville Lautanala
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ none: false
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: 2.1.7
21
+ name: ruby-openid
22
+ prerelease: false
23
+ requirement: !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ! '>='
27
+ - !ruby/object:Gem::Version
28
+ version: 2.1.7
29
+ type: :runtime
30
+ - !ruby/object:Gem::Dependency
31
+ version_requirements: !ruby/object:Gem::Requirement
32
+ none: false
33
+ requirements:
34
+ - - ~>
35
+ - !ruby/object:Gem::Version
36
+ version: '3.0'
37
+ name: redis
38
+ prerelease: false
39
+ requirement: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: '3.0'
45
+ type: :runtime
46
+ - !ruby/object:Gem::Dependency
47
+ version_requirements: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ~>
51
+ - !ruby/object:Gem::Version
52
+ version: '1.3'
53
+ name: bundler
54
+ prerelease: false
55
+ requirement: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: '1.3'
61
+ type: :development
62
+ - !ruby/object:Gem::Dependency
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ name: rake
70
+ prerelease: false
71
+ requirement: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ - !ruby/object:Gem::Dependency
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ~>
83
+ - !ruby/object:Gem::Version
84
+ version: '2.13'
85
+ name: rspec
86
+ prerelease: false
87
+ requirement: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ~>
91
+ - !ruby/object:Gem::Version
92
+ version: '2.13'
93
+ type: :development
94
+ - !ruby/object:Gem::Dependency
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ name: mock_redis
102
+ prerelease: false
103
+ requirement: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ type: :development
110
+ description: Use Redis to store OpenID associations and nonces with ruby-openid
111
+ email:
112
+ - lautis@gmail.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - .travis.yml
119
+ - Gemfile
120
+ - LICENSE.txt
121
+ - README.md
122
+ - Rakefile
123
+ - lib/openid-store-redis.rb
124
+ - lib/openid/store/redis.rb
125
+ - lib/openid/store/redis/version.rb
126
+ - openid-store-redis.gemspec
127
+ - spec/openid/store/redis_spec.rb
128
+ - spec/spec_helper.rb
129
+ homepage: ''
130
+ licenses:
131
+ - MIT
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ segments:
142
+ - 0
143
+ hash: 881735339377992324
144
+ version: '0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ segments:
151
+ - 0
152
+ hash: 881735339377992324
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 1.8.23
157
+ signing_key:
158
+ specification_version: 3
159
+ summary: A Redis storage backend for ruby-openid
160
+ test_files:
161
+ - spec/openid/store/redis_spec.rb
162
+ - spec/spec_helper.rb