oo_auth 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e5200d37778ac2220a1003d8551caf8c12d69fbd
4
+ data.tar.gz: 5a10c0b125e737c49ca54ae444f9205bb06671e3
5
+ SHA512:
6
+ metadata.gz: d4f0c1423e3e41f26ff2bce7acdb83cb42a7b623732385d7259a0cb88f722eb8b8779b2481aded7f454c197e2f47c94d4b00ef88fa39b83ade09323e1399a6ea
7
+ data.tar.gz: 32d8a1dc341e408ca95fcb50fec6fa58a7621309ea7c95de0286c9a64013b08e5b0315ac5f4f236e6e007e9567fbf6b7e941d93867d306932070dd85d6fd9444
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ 0.0.1 - 2013-11-06
2
+
3
+ * First release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Matthias Grosser
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ [![Gem Version](https://badge.fury.io/rb/oo_auth.png)](http://badge.fury.io/rb/oo_auth) [![Code Climate](https://codeclimate.com/github/mtgrosser/oo_auth.png)](https://codeclimate.com/github/mtgrosser/oo_auth)
2
+
3
+ # oo_auth
4
+
5
+ OAuth Out Of Band - Sign, verify and authorize OAuth requests
6
+
7
+ OoAuth is a stripped-down implementation of the OAuth 1.0a protocol.
8
+
9
+ It only cares for signing and verifying OAuth requests, supporting both
10
+ ```Net::HTTP``` and ```ActionDispatch::Request```.
11
+
12
+ OoAuth does not include any models or controllers dealing with token and
13
+ secret exchange, storage or lookup. Instead, it offers a simplistic API
14
+ where you can hook your own implementations as desired.
15
+
16
+ OoAuth comes with optional Redis support for short-time high performance storage
17
+ of OAuth nonces.
18
+
19
+ It can be used for implementing OAuth consumers as well as providers.
20
+
21
+ ## Install
22
+
23
+ In your Gemfile:
24
+
25
+ ```ruby
26
+ gem 'oo_auth'
27
+ ```
28
+
29
+ ## Prerequisites
30
+
31
+ OoAuth requires your application to provide stores for authorization tokens
32
+ and OAuth nonces.
33
+
34
+ OoAuth stores can be simple lambdas or regular ruby objects.
35
+
36
+ ### Authorization store
37
+
38
+ The authorization store should return an instance of ```OoAuth::Credentials```.
39
+ It can either be a lambda or an object implementing the `authorization` method.
40
+
41
+ ```ruby
42
+ # your own implementation in SomeClass model
43
+ OoAuth.authorization_store = lambda { |consumer_key, token| SomeClass.find_by_tokens(consumer_key, token) }
44
+ ```
45
+ ```ruby
46
+ # direct lookup
47
+ OoAuth.authorization_store = User
48
+ ```
49
+ ### Nonce store
50
+ ```ruby
51
+ require 'oo_auth/nonce/redis_store'
52
+
53
+ OoAuth.nonce_store = OoAuth::Nonce::RedisStore.new(namespace: 'foobar')
54
+ ```
55
+ ## Use
56
+
57
+ ### OAuth consumer
58
+
59
+ ```ruby
60
+ http = Net::HTTP.new('photos.example.net', Net::HTTP.http_default_port)
61
+ request = Net::HTTP::Get.new('/photos?file=vacation.jpg&size=original')
62
+
63
+ credentials = OoAuth::Credentials.new('consumer_key',
64
+ 'consumer_secret',
65
+ 'access_token',
66
+ 'access_token_secret')
67
+
68
+ OoAuth.sign!(http, request, credentials)
69
+
70
+ request['Authorization']
71
+ => "OAuth oauth_version=\"1.0\", oauth_nonce=\"ly9V24IvFMhEGSlGW1tPniUVnVzQkWvn4W6Bwtmc4\", oauth_timestamp=\"1384116351\", oauth_signature_method=\"HMAC-SHA1\", oauth_consumer_key=\"consumer_key\", oauth_token=\"access_token\", oauth_signature=\"5G1ktyWhicZGnSu2AKkjok9%2BMPo%3D\""
72
+ ```
73
+
74
+ ### OAuth provider
75
+
76
+ ```ruby
77
+ class FoobarController < ApplicationController
78
+
79
+ before_filter :oauth_required
80
+
81
+ private
82
+
83
+ def oauth_required
84
+ if authorization = OoAuth.authorize!(request)
85
+ self.current_user = authorization.user
86
+ else
87
+ render nothing: true, status: 401
88
+ end
89
+ end
90
+ ```
91
+
92
+
93
+ ## TODO
94
+
95
+ * Support POST body signing
@@ -0,0 +1,3 @@
1
+ module OoAuth
2
+ class ConfigurationError < StandardError; end
3
+ end
@@ -0,0 +1,19 @@
1
+ module OoAuth
2
+
3
+ # request tokens are passed between the consumer and the provider out of
4
+ # band (i.e. callbacks cannot be used), per section 6.1.1
5
+ OUT_OF_BAND = 'oob'
6
+
7
+ # FIXME: ordering
8
+ # required parameters, per sections 6.1.1, 6.3.1, and 7
9
+ PARAMETERS = %w(oauth_callback oauth_consumer_key oauth_token oauth_signature_method oauth_timestamp oauth_nonce oauth_verifier oauth_version oauth_signature oauth_body_hash)
10
+
11
+ # reserved character regexp, per section 5.1
12
+ RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~]/
13
+
14
+ # OoAuth only supports HMAC-SHA1
15
+ SIGNATURE_METHOD = 'HMAC-SHA1'
16
+
17
+ MAX_TIMESTAMP_DEVIATION = 5 * 60
18
+
19
+ end
@@ -0,0 +1,22 @@
1
+ module OoAuth
2
+ class Credentials
3
+ AUTH_ATTRIBUTES = [:consumer_key, :consumer_secret, :token, :token_secret]
4
+
5
+ attr_reader *AUTH_ATTRIBUTES
6
+
7
+ class << self
8
+ def generate
9
+ new(*4.times.collect { OoAuth.generate_key })
10
+ end
11
+ end
12
+
13
+ def initialize(consumer_key, consumer_secret, token, token_secret)
14
+ @consumer_key, @consumer_secret, @token, @token_secret = consumer_key, consumer_secret, token, token_secret
15
+ end
16
+
17
+ def attributes
18
+ AUTH_ATTRIBUTES.inject({}) { |hsh, attr| hsh.update(attr => send(attr)) }
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module OoAuth
2
+ class Nonce
3
+ class AbstractStore
4
+
5
+ class << self
6
+ def create(nonce)
7
+ #
8
+ end
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ module OoAuth
2
+ class Nonce
3
+ class RedisStore < AbstractStore
4
+ attr_reader :redis, :namespace, :ttl
5
+
6
+ def initialize(options = {})
7
+ options.symbolize_keys!
8
+ @namespace = options.delete(:namespace)
9
+ @ttl = options.delete(:ttl) || 15.minutes
10
+ @redis = Redis.new(options)
11
+ end
12
+
13
+ def create(nonce)
14
+ return nonce if @redis.set(key(nonce), '1', { nx: true, ex: ttl })
15
+ false
16
+ rescue Errno::ECONNREFUSED
17
+ false
18
+ end
19
+
20
+ protected
21
+
22
+ def key(nonce)
23
+ "#{@namespace}:oo_auth_nonce:#{nonce.timestamp}:#{nonce.value}"
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,48 @@
1
+ module OoAuth
2
+ class Nonce
3
+ MAX_LENGTH = 255
4
+
5
+ attr_reader :value, :timestamp, :errors
6
+
7
+ class << self
8
+ def store
9
+ OoAuth.nonce_store || fail(ConfigurationError, 'no nonce store set')
10
+ end
11
+
12
+ def create(nonce)
13
+ if store.respond_to?(:call)
14
+ store.call(nonce)
15
+ elsif store.respond_to?(:create)
16
+ store.create(nonce)
17
+ else
18
+ fail ConfigurationError, 'nonce store not callable'
19
+ end
20
+ end
21
+
22
+ def remember(value, timestamp)
23
+ new(value, timestamp).save
24
+ end
25
+
26
+ def generate
27
+ new(OoAuth.generate_nonce, Time.now.utc.to_i)
28
+ end
29
+ end
30
+
31
+ def initialize(value, timestamp)
32
+ @value, @timestamp = value, timestamp.to_i
33
+ end
34
+
35
+ def valid?
36
+ @errors = []
37
+ @errors << 'nonce value cannot be blank' if value.to_s == ''
38
+ @errors << 'nonce value too big' if value.size > MAX_LENGTH
39
+ @errors << 'illegal nonce timestamp' if timestamp <= 0
40
+ @errors.empty?
41
+ end
42
+
43
+ def save
44
+ !!(valid? && self.class.create(self))
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,135 @@
1
+ module OoAuth
2
+ class RequestProxy
3
+
4
+ attr_reader :port, :ssl, :host, :path, :headers, :method, :body
5
+
6
+ class << self
7
+
8
+
9
+ # Parse an Authorization / WWW-Authenticate header into a hash. Takes care of unescaping and
10
+ # removing surrounding quotes. Raises a OAuth::Problem if the header is not parsable into a
11
+ # valid hash. Does not validate the keys or values.
12
+ #
13
+ # hash = parse(headers['Authorization'] || headers['WWW-Authenticate'])
14
+ # hash['oauth_timestamp']
15
+ # #=>"1234567890"
16
+ #
17
+ def parse(header)
18
+ header = header.to_s
19
+ return unless header.start_with?('OAuth ')
20
+ # decompose
21
+ params = header[6, header.length].split(',').inject({}) do |hsh, str|
22
+ key, value = str.split('=').map { |s| OoAuth.unescape(s.strip) }
23
+ if PARAMETERS.include?(key)
24
+ hsh[key] = value.sub(/^\"(.*)\"$/, '\1')
25
+ end
26
+ hsh
27
+ end
28
+ end
29
+ end
30
+
31
+ def initialize(*args)
32
+ case args.size
33
+ when 1 # ActionDispatch request
34
+ request = args[0]
35
+ @port = request.port
36
+ @ssl = request.ssl?
37
+ @path = request.fullpath
38
+ @host = request.host
39
+ @headers = request.headers
40
+ when 2 # Net:HTTP request
41
+ http, request = args[0], args[1]
42
+ @port = http.port
43
+ @ssl = http.use_ssl?
44
+ @path = request.path
45
+ @host = http.address
46
+ @headers = request
47
+ else
48
+ raise ArgumentError, 'wrong number of arguments'
49
+ end
50
+ @method = request.method
51
+ @body = request.body
52
+ end
53
+
54
+ def normalized_request_uri
55
+ if self.port == Net::HTTP.default_port
56
+ scheme, port = :http, nil
57
+ elsif self.port == Net::HTTP.https_default_port
58
+ scheme, port = :https, nil
59
+ elsif ssl
60
+ scheme, port = :https, self.port
61
+ else
62
+ scheme, port = :http, self.port
63
+ end
64
+
65
+ uri = "#{scheme}://#{host.downcase}"
66
+ uri += ":#{port}" if port
67
+ uri += path.split('?').first
68
+ uri
69
+ end
70
+
71
+ def oauth_params
72
+ self.class.parse(authorization)
73
+ end
74
+
75
+ def oauth_params_without_signature
76
+ params = oauth_params
77
+ params.delete('oauth_signature')
78
+ params
79
+ end
80
+
81
+ def authorization
82
+ headers['Authorization']
83
+ end
84
+
85
+ def authorization=(header)
86
+ headers['Authorization'] = header
87
+ end
88
+
89
+ PARAMETERS.each do |parameter|
90
+ define_method "#{parameter[6..-1]}" do
91
+ oauth_params[parameter]
92
+ end
93
+ end
94
+
95
+ def post?
96
+ 'POST' == method
97
+ end
98
+
99
+ def signature_base_string(params = {})
100
+ encoded_params = params_encode(params_array(self) + params_array(params))
101
+ OoAuth.encode(method, normalized_request_uri, encoded_params)
102
+ end
103
+
104
+ # FIXME: cf nested params implementation in oauth gem
105
+ # TODO: support oauth body signature for non-formencoded content types
106
+ def params_array(object)
107
+ case object
108
+ when Array then object
109
+ when Hash then object.to_a
110
+ when RequestProxy
111
+ tmp = object.path.split('?')
112
+ params = tmp[1] ? params_decode(tmp[1]) : []
113
+ if object.post? && object.headers['Content-Type'].to_s.start_with?('application/x-www-form-urlencoded')
114
+ params.concat params_decode(object.body)
115
+ end
116
+ params
117
+ else
118
+ raise "error: cannot convert #{object.class} object to params array"
119
+ end
120
+ end
121
+
122
+ def params_decode(string)
123
+ string.split('&').each_with_object([]) do |param, array|
124
+ k, v = *param.split('=')
125
+ array << [OoAuth.unescape(k), v && OoAuth.unescape(v)]
126
+ end
127
+ end
128
+
129
+ # cf. http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2
130
+ def params_encode(params)
131
+ params.map { |k, v| [OoAuth.escape(k), OoAuth.escape(v)] }.sort.map { |k, v| "#{k}=#{v}" }.join('&')
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,55 @@
1
+ module OoAuth
2
+ module Signature
3
+
4
+ class << self
5
+ def hmac_sha1_signature(base_string, consumer_secret, token_secret)
6
+ Base64.strict_encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, OoAuth.encode(consumer_secret, token_secret), base_string))
7
+ end
8
+
9
+ def calculate_signature(proxy, credentials, params)
10
+ hmac_sha1_signature(proxy.signature_base_string(params), credentials.consumer_secret, credentials.token_secret)
11
+ end
12
+
13
+ def sign!(proxy, credentials)
14
+ params = {
15
+ oauth_version: '1.0',
16
+ oauth_nonce: OoAuth.generate_nonce,
17
+ oauth_timestamp: OoAuth.timestamp,
18
+ oauth_signature_method: SIGNATURE_METHOD,
19
+ oauth_consumer_key: credentials.consumer_key,
20
+ oauth_token: credentials.token
21
+ }
22
+
23
+ params[:oauth_signature] = calculate_signature(proxy, credentials, params)
24
+
25
+ proxy.authorization = authorization_header(params)
26
+ end
27
+
28
+ # Check signature validity without remembering nonce - DO NOT use to authorize actual requests
29
+ def valid?(proxy, credentials)
30
+ verify_timestamp!(proxy) &&
31
+ calculate_signature(proxy, credentials, proxy.oauth_params_without_signature) == proxy.signature
32
+ end
33
+
34
+ # Verify signature and remember nonce - use this to authorize actual requests
35
+ def verify!(proxy, credentials)
36
+ valid?(proxy, credentials) && remember_nonce!(proxy)
37
+ end
38
+
39
+ private
40
+
41
+ def verify_timestamp!(proxy)
42
+ (OoAuth.timestamp - proxy.timestamp.to_i).abs < MAX_TIMESTAMP_DEVIATION
43
+ end
44
+
45
+ def remember_nonce!(proxy)
46
+ Nonce.remember(proxy.nonce, proxy.timestamp)
47
+ end
48
+
49
+ def authorization_header(params)
50
+ 'OAuth ' + params.map { |k, v| "#{OoAuth.escape(k)}=\"#{OoAuth.escape(v)}\"" }.join(', ')
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ module OoAuth
2
+ VERSION = '0.0.1'
3
+ end
data/lib/oo_auth.rb ADDED
@@ -0,0 +1,94 @@
1
+ require 'openssl'
2
+ require 'uri'
3
+ require 'net/http'
4
+ require 'base64'
5
+
6
+ require 'oo_auth/version'
7
+ require 'oo_auth/constants'
8
+ require 'oo_auth/configuration_error'
9
+ require 'oo_auth/nonce'
10
+ require 'oo_auth/nonce/abstract_store'
11
+ require 'oo_auth/request_proxy'
12
+ require 'oo_auth/credentials'
13
+ require 'oo_auth/signature'
14
+
15
+ module OoAuth
16
+
17
+ class << self
18
+ # Initialize with instance of store
19
+ # OoAuth.nonce_store = OoAuth::Nonce::RedisStore.new(namespace: 'foo')
20
+ attr_accessor :nonce_store
21
+
22
+
23
+ # Define a lookup method for access token verification
24
+ # It should be callable (proc) or provide an +authorization+ method,
25
+ # with the argument being the consumer key and token.
26
+ # The proc or method call should return
27
+ # - if the consumer key/token combination exists:
28
+ # an object which responding to +credentials+ with an
29
+ # initialized instance of
30
+ # OoAuth::Credentials
31
+ # - nil otherwise.
32
+ attr_accessor :authorization_store
33
+
34
+ # Generate a random key of up to +size+ bytes. The value returned is Base64 encoded with non-word
35
+ # characters removed.
36
+ def generate_key(size = 32)
37
+ Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, '')
38
+ end
39
+
40
+ alias_method :generate_nonce, :generate_key
41
+
42
+ # Escape +value+ by URL encoding all non-reserved character.
43
+ #
44
+ # See Also: {OAuth core spec version 1.0, section 5.1}[http://oauth.net/core/1.0#rfc.section.5.1]
45
+ def escape(value)
46
+ URI.escape(value.to_s, RESERVED_CHARACTERS)
47
+ rescue ArgumentError
48
+ URI.escape(value.to_s.force_encoding(Encoding::UTF_8), RESERVED_CHARACTERS)
49
+ end
50
+
51
+ def unescape(value)
52
+ URI.unescape(value.gsub('+', '%2B'))
53
+ end
54
+
55
+ # cf. http://tools.ietf.org/html/rfc5849#section-3.4.1.1
56
+ # cf. http://tools.ietf.org/html/rfc5849#section-3.4.4
57
+ def encode(*components)
58
+ components.map { |component| OoAuth.escape(component) }.join('&')
59
+ end
60
+
61
+ # Current UTC timestamp
62
+ def timestamp
63
+ Time.now.utc.to_i
64
+ end
65
+
66
+ def authorization(consumer_key, token)
67
+ if authorization_store.respond_to?(:call)
68
+ authorization_store.call(consumer_key, token)
69
+ elsif authorization_store.respond_to?(:authorization)
70
+ authorization_store.authorization(consumer_key, token)
71
+ else
72
+ fail ConfigurationError, 'authorization store not callable'
73
+ end
74
+ end
75
+
76
+ # Use this to sign Net::HTTP or ActionDispatch requests
77
+ def sign!(*args)
78
+ credentials = args.pop
79
+ proxy = RequestProxy.new(*args)
80
+ Signature.sign!(proxy, credentials)
81
+ end
82
+
83
+ # Use this in your controllers to verify the OAuth signature
84
+ # of a request.
85
+ def authorize!(*args)
86
+ proxy = RequestProxy.new(*args)
87
+ return unless authorization = self.authorization(proxy.consumer_key, proxy.token)
88
+ return unless Signature.verify!(proxy, authorization.credentials)
89
+ authorization
90
+ end
91
+
92
+ end
93
+
94
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oo_auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Matthias Grosser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: byebug
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: simplecov
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.8.7
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.8.7
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '4.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '4.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: timecop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.6.3
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.6.3
83
+ description: Out Of Band OAuth
84
+ email: mtgrosser@gmx.net
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - lib/oo_auth/configuration_error.rb
90
+ - lib/oo_auth/constants.rb
91
+ - lib/oo_auth/credentials.rb
92
+ - lib/oo_auth/nonce/abstract_store.rb
93
+ - lib/oo_auth/nonce/redis_store.rb
94
+ - lib/oo_auth/nonce.rb
95
+ - lib/oo_auth/request_proxy.rb
96
+ - lib/oo_auth/signature.rb
97
+ - lib/oo_auth/version.rb
98
+ - lib/oo_auth.rb
99
+ - LICENSE
100
+ - README.md
101
+ - CHANGELOG
102
+ homepage: http://github.com/mtgrosser/oo_auth
103
+ licenses:
104
+ - MIT
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.0.3
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: OAuth without the callbacks
126
+ test_files: []