oauthenticator 0.1.1 → 0.1.2
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 +2 -2
- data/lib/oauthenticator/signed_request.rb +75 -60
- data/lib/oauthenticator/version.rb +1 -1
- data/test/config_methods_test.rb +41 -0
- data/test/helper.rb +18 -0
- data/test/oauthenticator_test.rb +17 -17
- metadata +7 -3
data/README.md
CHANGED
@@ -37,12 +37,12 @@ require 'oauthenticator'
|
|
37
37
|
module AwesomeOAuthConfig
|
38
38
|
# check for an existing nonce, coupled with the timestamp
|
39
39
|
def nonce_used?
|
40
|
-
|
40
|
+
OAuthNonce.where(:nonce => nonce, :timestamp => timestamp).any?
|
41
41
|
end
|
42
42
|
|
43
43
|
# nonce is used, store it so that in the future #nonce_used? will return true correctly
|
44
44
|
def use_nonce!
|
45
|
-
|
45
|
+
OAuthNonce.create!(:nonce => nonce, :timestamp => timestamp)
|
46
46
|
end
|
47
47
|
|
48
48
|
# number seconds in the past and the future for which we'll consider a request authentic
|
@@ -89,79 +89,94 @@ module OAuthenticator
|
|
89
89
|
elsif authorization !~ /\Aoauth\s/i
|
90
90
|
{'Authorization' => ["Authorization scheme is not OAuth; received Authorization: #{authorization}"]}
|
91
91
|
else
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
92
|
+
to_rescue = SimpleOAuth.const_defined?(:ParseError) ? SimpleOAuth::ParseError : StandardError
|
93
|
+
begin
|
94
|
+
oauth_header_params
|
95
|
+
rescue to_rescue
|
96
|
+
parse_exception = $!
|
97
|
+
end
|
98
|
+
if parse_exception
|
99
|
+
if parse_exception.class.name == 'SimpleOAuth::ParseError'
|
100
|
+
message = parse_exception.message
|
101
|
+
else
|
102
|
+
message = "Authorization header is not a properly-formed OAuth 1.0 header."
|
103
|
+
end
|
104
|
+
{'Authorization' => [message]}
|
99
105
|
else
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
errors['Authorization oauth_timestamp'] << "is
|
106
|
+
errors = Hash.new { |h,k| h[k] = [] }
|
107
|
+
|
108
|
+
# timestamp
|
109
|
+
if !timestamp?
|
110
|
+
errors['Authorization oauth_timestamp'] << "is missing"
|
111
|
+
elsif timestamp !~ /\A\s*\d+\s*\z/
|
112
|
+
errors['Authorization oauth_timestamp'] << "is not an integer - got: #{timestamp}"
|
113
|
+
else
|
114
|
+
timestamp_i = timestamp.to_i
|
115
|
+
if timestamp_i < Time.now.to_i - timestamp_valid_past
|
116
|
+
errors['Authorization oauth_timestamp'] << "is too old: #{timestamp}"
|
117
|
+
elsif timestamp_i > Time.now.to_i + timestamp_valid_future
|
118
|
+
errors['Authorization oauth_timestamp'] << "is too far in the future: #{timestamp}"
|
119
|
+
end
|
105
120
|
end
|
106
|
-
end
|
107
121
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
122
|
+
# oauth version
|
123
|
+
if version? && version != '1.0'
|
124
|
+
errors['Authorization oauth_version'] << "must be 1.0; got: #{version}"
|
125
|
+
end
|
112
126
|
|
113
|
-
|
114
|
-
|
127
|
+
# she's filled with secrets
|
128
|
+
secrets = {}
|
115
129
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
130
|
+
# consumer / client application
|
131
|
+
if !consumer_key?
|
132
|
+
errors['Authorization oauth_consumer_key'] << "is missing"
|
133
|
+
else
|
134
|
+
secrets[:consumer_secret] = consumer_secret
|
135
|
+
if !secrets[:consumer_secret]
|
136
|
+
errors['Authorization oauth_consumer_key'] << 'is invalid'
|
137
|
+
end
|
123
138
|
end
|
124
|
-
end
|
125
139
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
140
|
+
# access token
|
141
|
+
if token?
|
142
|
+
secrets[:token_secret] = access_token_secret
|
143
|
+
if !secrets[:token_secret]
|
144
|
+
errors['Authorization oauth_token'] << 'is invalid'
|
145
|
+
elsif !access_token_belongs_to_consumer?
|
146
|
+
errors['Authorization oauth_token'] << 'does not belong to the specified consumer'
|
147
|
+
end
|
133
148
|
end
|
134
|
-
end
|
135
149
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
150
|
+
# nonce
|
151
|
+
if !nonce?
|
152
|
+
errors['Authorization oauth_nonce'] << "is missing"
|
153
|
+
elsif nonce_used?
|
154
|
+
errors['Authorization oauth_nonce'] << "has already been used"
|
155
|
+
end
|
142
156
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
157
|
+
# signature method
|
158
|
+
if !signature_method?
|
159
|
+
errors['Authorization oauth_signature_method'] << "is missing"
|
160
|
+
elsif !allowed_signature_methods.any? { |sm| signature_method.downcase == sm.downcase }
|
161
|
+
errors['Authorization oauth_signature_method'] << "must be one of " +
|
162
|
+
"#{allowed_signature_methods.join(', ')}; got: #{signature_method}"
|
163
|
+
end
|
150
164
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
165
|
+
# signature
|
166
|
+
if !signature?
|
167
|
+
errors['Authorization oauth_signature'] << "is missing"
|
168
|
+
end
|
155
169
|
|
156
|
-
|
157
|
-
|
158
|
-
else
|
159
|
-
# proceed to check signature
|
160
|
-
if !simple_oauth_header.valid?(secrets)
|
161
|
-
{'Authorization oauth_signature' => ['is invalid']}
|
170
|
+
if errors.any?
|
171
|
+
errors
|
162
172
|
else
|
163
|
-
|
164
|
-
|
173
|
+
# proceed to check signature
|
174
|
+
if !simple_oauth_header.valid?(secrets)
|
175
|
+
{'Authorization oauth_signature' => ['is invalid']}
|
176
|
+
else
|
177
|
+
use_nonce!
|
178
|
+
nil
|
179
|
+
end
|
165
180
|
end
|
166
181
|
end
|
167
182
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('.', File.dirname(__FILE__)))
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
describe OAuthenticator::SignedRequest do
|
6
|
+
%w(timestamp_valid_period consumer_secret access_token_secret nonce_used? use_nonce! access_token_belongs_to_consumer?).each do |method_without_default|
|
7
|
+
it "complains when #{method_without_default} is not implemented" do
|
8
|
+
exc = assert_raises(NotImplementedError) do
|
9
|
+
OAuthenticator::SignedRequest.new({}).public_send(method_without_default)
|
10
|
+
end
|
11
|
+
assert_match /included in a subclass of OAuthenticator::SignedRequest/, exc.message
|
12
|
+
end
|
13
|
+
it "uses the method #{method_without_default} when implemented" do
|
14
|
+
called = false
|
15
|
+
mod = Module.new { define_method(method_without_default) { called = true } }
|
16
|
+
OAuthenticator::SignedRequest.including_config(mod).new({}).public_send(method_without_default)
|
17
|
+
assert called
|
18
|
+
end
|
19
|
+
end
|
20
|
+
it "complains when a method without a default is not implemented, using middleware" do
|
21
|
+
exc = assert_raises(NotImplementedError) do
|
22
|
+
OAuthenticator::Middleware.new(proc {}, {:config_methods => Module.new}).call({'HTTP_AUTHORIZATION' => %q(OAuth oauth_timestamp="1")})
|
23
|
+
end
|
24
|
+
assert_match /passed to OAuthenticator::Middleware using the option :config_methods./, exc.message
|
25
|
+
end
|
26
|
+
it "complains middleware is not given config methods" do
|
27
|
+
assert_raises(ArgumentError) do
|
28
|
+
OAuthenticator::Middleware.new(proc {})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
it 'uses timestamp_valid_period if that is implemented but timestamp_valid_past or timestamp_valid_future is not' do
|
32
|
+
called = 0
|
33
|
+
mod = Module.new { define_method(:timestamp_valid_period) { called +=1 } }
|
34
|
+
OAuthenticator::SignedRequest.including_config(mod).new({}).public_send(:timestamp_valid_future)
|
35
|
+
OAuthenticator::SignedRequest.including_config(mod).new({}).public_send(:timestamp_valid_past)
|
36
|
+
assert_equal 2, called
|
37
|
+
end
|
38
|
+
it 'uses the default value for allowed signature methods' do
|
39
|
+
assert_equal OAuthenticator::SignedRequest::VALID_SIGNATURE_METHODS, OAuthenticator::SignedRequest.new({}).allowed_signature_methods
|
40
|
+
end
|
41
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('../lib', File.dirname(__FILE__)))
|
2
|
+
|
3
|
+
require 'simplecov'
|
4
|
+
|
5
|
+
require 'debugger'
|
6
|
+
Debugger.start
|
7
|
+
|
8
|
+
# NO EXPECTATIONS
|
9
|
+
ENV["MT_NO_EXPECTATIONS"]
|
10
|
+
|
11
|
+
require 'minitest/autorun'
|
12
|
+
require 'minitest/reporters'
|
13
|
+
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
|
14
|
+
|
15
|
+
require 'rack/test'
|
16
|
+
require 'timecop'
|
17
|
+
|
18
|
+
require 'oauthenticator'
|
data/test/oauthenticator_test.rb
CHANGED
@@ -1,21 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
|
-
require '
|
4
|
-
|
5
|
-
require 'debugger'
|
6
|
-
Debugger.start
|
7
|
-
|
8
|
-
# NO EXPECTATIONS
|
9
|
-
ENV["MT_NO_EXPECTATIONS"]
|
10
|
-
|
11
|
-
require 'minitest/autorun'
|
12
|
-
require 'minitest/reporters'
|
13
|
-
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
|
14
|
-
|
15
|
-
require 'rack/test'
|
16
|
-
require 'timecop'
|
17
|
-
|
18
|
-
require 'oauthenticator'
|
2
|
+
proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('.', File.dirname(__FILE__)))
|
3
|
+
require 'helper'
|
19
4
|
|
20
5
|
# config methods for testing OAuthenticator. simple
|
21
6
|
module OAuthenticatorTestConfigMethods
|
@@ -182,6 +167,21 @@ describe OAuthenticator::Middleware do
|
|
182
167
|
assert_response(401, /Authorization scheme is not OAuth/, *oapp.call({'HTTP_AUTHORIZATION' => 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='}))
|
183
168
|
end
|
184
169
|
|
170
|
+
describe 'invalid Authorization header' do
|
171
|
+
if SimpleOAuth.const_defined?(:ParseError)
|
172
|
+
it 'does not prefix with oauth_' do
|
173
|
+
assert_response(401, /Could not parse Authorization header/, *oapp.call({'HTTP_AUTHORIZATION' => %q(OAuth client_app_key="test_client_app_key")}))
|
174
|
+
end
|
175
|
+
it 'has something unparseable' do
|
176
|
+
assert_response(401, /Could not parse Authorization header/, *oapp.call({'HTTP_AUTHORIZATION' => %q(OAuth <client-app-key>test_client_app_key</client-app-key>)}))
|
177
|
+
end
|
178
|
+
else
|
179
|
+
it 'has something unparseable' do
|
180
|
+
assert_response(401, /Authorization header is not a properly-formed OAuth 1.0 header./, *oapp.call({'HTTP_AUTHORIZATION' => %q(OAuth <client-app-key>test_client_app_key</client-app-key>)}))
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
185
|
it 'omits timestamp' do
|
186
186
|
Timecop.travel Time.at 1391021695
|
187
187
|
consumer # cause this to be created
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oauthenticator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-03-
|
12
|
+
date: 2014-03-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -222,7 +222,7 @@ dependencies:
|
|
222
222
|
description: OAuthenticator authenticates OAuth 1.0 signed requests, primarily as
|
223
223
|
a middleware, and forms useful error messages when authentication fails.
|
224
224
|
email:
|
225
|
-
- ethan@
|
225
|
+
- ethan@unth
|
226
226
|
executables: []
|
227
227
|
extensions: []
|
228
228
|
extra_rdoc_files: []
|
@@ -235,7 +235,9 @@ files:
|
|
235
235
|
- lib/oauthenticator/config_methods.rb
|
236
236
|
- lib/oauthenticator/signed_request.rb
|
237
237
|
- lib/oauthenticator/version.rb
|
238
|
+
- test/helper.rb
|
238
239
|
- test/oauthenticator_test.rb
|
240
|
+
- test/config_methods_test.rb
|
239
241
|
homepage: https://github.com/notEthan/oauthenticator
|
240
242
|
licenses:
|
241
243
|
- MIT
|
@@ -262,5 +264,7 @@ signing_key:
|
|
262
264
|
specification_version: 3
|
263
265
|
summary: OAuth 1.0 request authentication middleware
|
264
266
|
test_files:
|
267
|
+
- test/helper.rb
|
265
268
|
- test/oauthenticator_test.rb
|
269
|
+
- test/config_methods_test.rb
|
266
270
|
has_rdoc:
|