oauthenticator 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|