tpitale-rack-oauth2-server 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +202 -0
- data/Gemfile +16 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +604 -0
- data/Rakefile +90 -0
- data/VERSION +1 -0
- data/bin/oauth2-server +206 -0
- data/lib/rack-oauth2-server.rb +4 -0
- data/lib/rack/oauth2/admin/css/screen.css +347 -0
- data/lib/rack/oauth2/admin/images/loading.gif +0 -0
- data/lib/rack/oauth2/admin/images/oauth-2.png +0 -0
- data/lib/rack/oauth2/admin/js/application.coffee +220 -0
- data/lib/rack/oauth2/admin/js/jquery.js +166 -0
- data/lib/rack/oauth2/admin/js/jquery.tmpl.js +414 -0
- data/lib/rack/oauth2/admin/js/protovis-r3.2.js +277 -0
- data/lib/rack/oauth2/admin/js/sammy.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.json.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.oauth2.js +142 -0
- data/lib/rack/oauth2/admin/js/sammy.storage.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.title.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.tmpl.js +5 -0
- data/lib/rack/oauth2/admin/js/underscore.js +722 -0
- data/lib/rack/oauth2/admin/views/client.tmpl +58 -0
- data/lib/rack/oauth2/admin/views/clients.tmpl +52 -0
- data/lib/rack/oauth2/admin/views/edit.tmpl +80 -0
- data/lib/rack/oauth2/admin/views/index.html +39 -0
- data/lib/rack/oauth2/admin/views/no_access.tmpl +4 -0
- data/lib/rack/oauth2/models.rb +27 -0
- data/lib/rack/oauth2/models/access_grant.rb +54 -0
- data/lib/rack/oauth2/models/access_token.rb +129 -0
- data/lib/rack/oauth2/models/auth_request.rb +61 -0
- data/lib/rack/oauth2/models/client.rb +93 -0
- data/lib/rack/oauth2/rails.rb +105 -0
- data/lib/rack/oauth2/server.rb +458 -0
- data/lib/rack/oauth2/server/admin.rb +250 -0
- data/lib/rack/oauth2/server/errors.rb +104 -0
- data/lib/rack/oauth2/server/helper.rb +147 -0
- data/lib/rack/oauth2/server/practice.rb +79 -0
- data/lib/rack/oauth2/server/railtie.rb +24 -0
- data/lib/rack/oauth2/server/utils.rb +30 -0
- data/lib/rack/oauth2/sinatra.rb +71 -0
- data/rack-oauth2-server.gemspec +24 -0
- data/rails/init.rb +11 -0
- data/test/admin/api_test.rb +228 -0
- data/test/admin/ui_test.rb +38 -0
- data/test/oauth/access_grant_test.rb +276 -0
- data/test/oauth/access_token_test.rb +311 -0
- data/test/oauth/authorization_test.rb +298 -0
- data/test/oauth/server_methods_test.rb +292 -0
- data/test/rails2/app/controllers/api_controller.rb +40 -0
- data/test/rails2/app/controllers/application_controller.rb +2 -0
- data/test/rails2/app/controllers/oauth_controller.rb +17 -0
- data/test/rails2/config/environment.rb +19 -0
- data/test/rails2/config/environments/test.rb +0 -0
- data/test/rails2/config/routes.rb +13 -0
- data/test/rails3/app/controllers/api_controller.rb +40 -0
- data/test/rails3/app/controllers/application_controller.rb +2 -0
- data/test/rails3/app/controllers/oauth_controller.rb +17 -0
- data/test/rails3/config/application.rb +19 -0
- data/test/rails3/config/environment.rb +2 -0
- data/test/rails3/config/routes.rb +12 -0
- data/test/setup.rb +120 -0
- data/test/sinatra/my_app.rb +69 -0
- metadata +145 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
require "test/setup"
|
2
|
+
|
3
|
+
class AdminUiTest < Test::Unit::TestCase
|
4
|
+
context "/" do
|
5
|
+
setup { get "/oauth/admin" }
|
6
|
+
should "return OK" do
|
7
|
+
assert_equal 200, last_response.status
|
8
|
+
end
|
9
|
+
should "return HTML page" do
|
10
|
+
assert_match "<html>", last_response.body
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "force SSL" do
|
15
|
+
setup { Server::Admin.force_ssl = true }
|
16
|
+
|
17
|
+
context "HTTP request" do
|
18
|
+
setup { get "/oauth/admin" }
|
19
|
+
|
20
|
+
should "redirect to HTTPS" do
|
21
|
+
assert_equal 302, last_response.status
|
22
|
+
assert_equal "https://example.org/oauth/admin", last_response.location
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "HTTPS request" do
|
27
|
+
setup { get "https://example.org/oauth/admin" }
|
28
|
+
|
29
|
+
should "serve request" do
|
30
|
+
assert_equal 200, last_response.status
|
31
|
+
assert_match "<html>", last_response.body
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
teardown { Server::Admin.force_ssl = false }
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
require "test/setup"
|
2
|
+
|
3
|
+
|
4
|
+
# 4. Obtaining an Access Token
|
5
|
+
class AccessGrantTest < Test::Unit::TestCase
|
6
|
+
module Helpers
|
7
|
+
|
8
|
+
def should_return_error(error)
|
9
|
+
should "respond with status 400 (Bad Request)" do
|
10
|
+
assert_equal 400, last_response.status
|
11
|
+
end
|
12
|
+
should "respond with JSON document" do
|
13
|
+
assert_equal "application/json", last_response.content_type
|
14
|
+
end
|
15
|
+
should "respond with error code #{error}" do
|
16
|
+
assert_equal error.to_s, JSON.parse(last_response.body)["error"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def should_respond_with_authentication_error(error)
|
21
|
+
should "respond with status 401 (Unauthorized)" do
|
22
|
+
assert_equal 401, last_response.status
|
23
|
+
end
|
24
|
+
should "respond with authentication method OAuth" do
|
25
|
+
assert_equal "OAuth", last_response["WWW-Authenticate"].split.first
|
26
|
+
end
|
27
|
+
should "respond with realm" do
|
28
|
+
assert_match " realm=\"example.org\"", last_response["WWW-Authenticate"]
|
29
|
+
end
|
30
|
+
should "respond with error code #{error}" do
|
31
|
+
assert_match " error=\"#{error}\"", last_response["WWW-Authenticate"]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def should_respond_with_access_token(scope = "read write")
|
36
|
+
should "respond with status 200" do
|
37
|
+
assert_equal 200, last_response.status
|
38
|
+
end
|
39
|
+
should "respond with JSON document" do
|
40
|
+
assert_equal "application/json", last_response.content_type
|
41
|
+
end
|
42
|
+
should "respond with cache control no-store" do
|
43
|
+
assert_equal "no-store", last_response["Cache-Control"]
|
44
|
+
end
|
45
|
+
should "not respond with error code" do
|
46
|
+
assert JSON.parse(last_response.body)["error"].nil?
|
47
|
+
end
|
48
|
+
should "response with access token" do
|
49
|
+
assert_match /[a-f0-9]{32}/i, JSON.parse(last_response.body)["access_token"]
|
50
|
+
end
|
51
|
+
should "response with scope" do
|
52
|
+
assert_equal scope || "", JSON.parse(last_response.body)["scope"]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
extend Helpers
|
59
|
+
|
60
|
+
def setup
|
61
|
+
super
|
62
|
+
# Get authorization code.
|
63
|
+
params = { :redirect_uri=>client.redirect_uri, :client_id=>client.id, :client_secret=>client.secret, :response_type=>"code",
|
64
|
+
:scope=>"read write", :state=>"bring this back" }
|
65
|
+
get "/oauth/authorize?" + Rack::Utils.build_query(params)
|
66
|
+
get last_response["Location"] if last_response.status == 303
|
67
|
+
authorization = last_response.body[/authorization:\s*(\S+)/, 1]
|
68
|
+
post "/oauth/grant", :authorization=>authorization
|
69
|
+
@code = Rack::Utils.parse_query(URI.parse(last_response["Location"]).query)["code"]
|
70
|
+
end
|
71
|
+
|
72
|
+
def request_none(scope = nil)
|
73
|
+
basic_authorize client.id, client.secret
|
74
|
+
# Note: This grant_type becomes "client_credentials" in version 11 of the OAuth 2.0 spec
|
75
|
+
params = { :grant_type=>"none", :scope=>"read write" }
|
76
|
+
params[:scope] = scope if scope
|
77
|
+
post "/oauth/access_token", params
|
78
|
+
end
|
79
|
+
|
80
|
+
def request_access_token(changes = nil)
|
81
|
+
params = { :client_id=>client.id, :client_secret=>client.secret, :scope=>"read write",
|
82
|
+
:grant_type=>"authorization_code", :code=>@code, :redirect_uri=>client.redirect_uri }.merge(changes || {})
|
83
|
+
basic_authorize params.delete(:client_id), params.delete(:client_secret)
|
84
|
+
post "/oauth/access_token", params
|
85
|
+
end
|
86
|
+
|
87
|
+
def request_with_username_password(username, password, scope = nil)
|
88
|
+
basic_authorize client.id, client.secret
|
89
|
+
params = { :grant_type=>"password" }
|
90
|
+
params[:scope] = scope if scope
|
91
|
+
params[:username] = username if username
|
92
|
+
params[:password] = password if password
|
93
|
+
post "/oauth/access_token", params
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# 4. Obtaining an Access Token
|
98
|
+
|
99
|
+
context "GET request" do
|
100
|
+
setup { get "/oauth/access_token" }
|
101
|
+
|
102
|
+
should "respond with status 405 (Method Not Allowed)" do
|
103
|
+
assert_equal 405, last_response.status
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "no client ID" do
|
108
|
+
setup { request_access_token :client_id=>nil }
|
109
|
+
should_respond_with_authentication_error :invalid_client
|
110
|
+
end
|
111
|
+
|
112
|
+
context "invalid client ID" do
|
113
|
+
setup { request_access_token :client_id=>"foobar" }
|
114
|
+
should_respond_with_authentication_error :invalid_client
|
115
|
+
end
|
116
|
+
|
117
|
+
context "client ID but no such client" do
|
118
|
+
setup { request_access_token :client_id=>"4cc7bc483321e814b8000000" }
|
119
|
+
should_respond_with_authentication_error :invalid_client
|
120
|
+
end
|
121
|
+
|
122
|
+
context "no client secret" do
|
123
|
+
setup { request_access_token :client_secret=>nil }
|
124
|
+
should_respond_with_authentication_error :invalid_client
|
125
|
+
end
|
126
|
+
|
127
|
+
context "wrong client secret" do
|
128
|
+
setup { request_access_token :client_secret=>"plain wrong" }
|
129
|
+
should_respond_with_authentication_error :invalid_client
|
130
|
+
end
|
131
|
+
|
132
|
+
context "client revoked" do
|
133
|
+
setup do
|
134
|
+
client.revoke!
|
135
|
+
request_access_token
|
136
|
+
end
|
137
|
+
should_respond_with_authentication_error :invalid_client
|
138
|
+
end
|
139
|
+
|
140
|
+
context "unsupported grant type" do
|
141
|
+
setup { request_access_token :grant_type=>"bogus" }
|
142
|
+
should_return_error :unsupported_grant_type
|
143
|
+
end
|
144
|
+
|
145
|
+
# 4.1.1. Authorization Code
|
146
|
+
|
147
|
+
context "no authorization code" do
|
148
|
+
setup { request_access_token :code=>nil }
|
149
|
+
should_return_error :invalid_grant
|
150
|
+
end
|
151
|
+
|
152
|
+
context "unknown authorization code" do
|
153
|
+
setup { request_access_token :code=>"unknown" }
|
154
|
+
should_return_error :invalid_grant
|
155
|
+
end
|
156
|
+
|
157
|
+
context "authorization code for different client" do
|
158
|
+
setup do
|
159
|
+
grant = Server::AccessGrant.create("foo bar", Server.register(:scope=>%w{read write}), "read write", nil)
|
160
|
+
request_access_token :code=>grant.code
|
161
|
+
end
|
162
|
+
should_return_error :invalid_grant
|
163
|
+
end
|
164
|
+
|
165
|
+
context "authorization code revoked" do
|
166
|
+
setup do
|
167
|
+
Server::AccessGrant.from_code(@code).revoke!
|
168
|
+
request_access_token
|
169
|
+
end
|
170
|
+
should_return_error :invalid_grant
|
171
|
+
end
|
172
|
+
|
173
|
+
context "mistmatched redirect URI" do
|
174
|
+
setup { request_access_token :redirect_uri=>"http://uberclient.dot/oz" }
|
175
|
+
should_return_error :invalid_grant
|
176
|
+
end
|
177
|
+
|
178
|
+
context "no redirect URI to match" do
|
179
|
+
setup do
|
180
|
+
@client = Server.register(:display_name=>"No rediret", :scope=>"read write")
|
181
|
+
grant = Server::AccessGrant.create("foo bar", client, "read write", nil)
|
182
|
+
request_access_token :code=>grant.code, :redirect_uri=>"http://uberclient.dot/oz"
|
183
|
+
end
|
184
|
+
should_respond_with_access_token
|
185
|
+
end
|
186
|
+
|
187
|
+
context "access grant expired" do
|
188
|
+
setup do
|
189
|
+
Timecop.travel 300 do
|
190
|
+
request_access_token
|
191
|
+
end
|
192
|
+
end
|
193
|
+
should_return_error :invalid_grant
|
194
|
+
end
|
195
|
+
|
196
|
+
context "access grant spent" do
|
197
|
+
setup do
|
198
|
+
request_access_token
|
199
|
+
request_access_token
|
200
|
+
end
|
201
|
+
should_return_error :invalid_grant
|
202
|
+
end
|
203
|
+
|
204
|
+
# 4.1.2. Resource Owner Password Credentials
|
205
|
+
|
206
|
+
context "no username" do
|
207
|
+
setup { request_with_username_password nil, "more" }
|
208
|
+
should_return_error :invalid_grant
|
209
|
+
end
|
210
|
+
|
211
|
+
context "no password" do
|
212
|
+
setup { request_with_username_password nil, "more" }
|
213
|
+
should_return_error :invalid_grant
|
214
|
+
end
|
215
|
+
|
216
|
+
context "not authorized" do
|
217
|
+
setup { request_with_username_password "cowbell", "less" }
|
218
|
+
should_return_error :invalid_grant
|
219
|
+
end
|
220
|
+
|
221
|
+
context "no scope specified" do
|
222
|
+
setup { request_with_username_password "cowbell", "more" }
|
223
|
+
should_respond_with_access_token "oauth-admin read write"
|
224
|
+
end
|
225
|
+
|
226
|
+
context "given scope" do
|
227
|
+
setup { request_with_username_password "cowbell", "more", "read" }
|
228
|
+
should_respond_with_access_token "read"
|
229
|
+
end
|
230
|
+
|
231
|
+
context "unsupported scope" do
|
232
|
+
setup { request_with_username_password "cowbell", "more", "read write math" }
|
233
|
+
should_return_error :invalid_scope
|
234
|
+
end
|
235
|
+
|
236
|
+
context "authenticator with 4 parameters" do
|
237
|
+
setup do
|
238
|
+
@old = config.authenticator
|
239
|
+
config.authenticator = lambda do |username, password, client_id, scope|
|
240
|
+
@client_id = client_id
|
241
|
+
@scope = scope
|
242
|
+
"Batman"
|
243
|
+
end
|
244
|
+
request_with_username_password "cowbell", "more", "read"
|
245
|
+
end
|
246
|
+
|
247
|
+
should_respond_with_access_token "read"
|
248
|
+
should "receive client identifier" do
|
249
|
+
assert_equal client.id, @client_id
|
250
|
+
end
|
251
|
+
should "receive scope" do
|
252
|
+
assert_equal %w{read}, @scope
|
253
|
+
end
|
254
|
+
|
255
|
+
teardown { config.authenticator = @old }
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
# 4.2. Access Token Response
|
260
|
+
|
261
|
+
context "using none" do
|
262
|
+
setup { request_none }
|
263
|
+
should_respond_with_access_token "read write"
|
264
|
+
end
|
265
|
+
|
266
|
+
context "using authorization code" do
|
267
|
+
setup { request_access_token }
|
268
|
+
should_respond_with_access_token "read write"
|
269
|
+
end
|
270
|
+
|
271
|
+
context "using username/password" do
|
272
|
+
setup { request_with_username_password "cowbell", "more", "read" }
|
273
|
+
should_respond_with_access_token "read"
|
274
|
+
end
|
275
|
+
|
276
|
+
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
require "test/setup"
|
2
|
+
|
3
|
+
|
4
|
+
# 5. Accessing a Protected Resource
|
5
|
+
class AccessTokenTest < Test::Unit::TestCase
|
6
|
+
module Helpers
|
7
|
+
|
8
|
+
def should_return_resource(content)
|
9
|
+
should "respond with status 200" do
|
10
|
+
assert_equal 200, last_response.status
|
11
|
+
end
|
12
|
+
should "respond with resource name" do
|
13
|
+
assert_equal content, last_response.body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def should_fail_authentication(error = nil)
|
18
|
+
should "respond with status 401 (Unauthorized)" do
|
19
|
+
assert_equal 401, last_response.status
|
20
|
+
end
|
21
|
+
should "respond with authentication method OAuth" do
|
22
|
+
assert_equal "OAuth", last_response["WWW-Authenticate"].split.first
|
23
|
+
end
|
24
|
+
should "respond with realm" do
|
25
|
+
assert_match " realm=\"example.org\"", last_response["WWW-Authenticate"]
|
26
|
+
end
|
27
|
+
if error
|
28
|
+
should "respond with error code #{error}" do
|
29
|
+
assert_match " error=\"#{error}\"", last_response["WWW-Authenticate"]
|
30
|
+
end
|
31
|
+
else
|
32
|
+
should "not respond with error code" do
|
33
|
+
assert !last_response["WWW-Authenticate"]["error="]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
extend Helpers
|
40
|
+
|
41
|
+
|
42
|
+
def setup
|
43
|
+
super
|
44
|
+
# Get authorization code.
|
45
|
+
params = { :redirect_uri=>client.redirect_uri, :client_id=>client.id, :client_secret=>client.secret, :response_type=>"code",
|
46
|
+
:scope=>"read write", :state=>"bring this back" }
|
47
|
+
get "/oauth/authorize?" + Rack::Utils.build_query(params)
|
48
|
+
get last_response["Location"] if last_response.status == 303
|
49
|
+
authorization = last_response.body[/authorization:\s*(\S+)/, 1]
|
50
|
+
post "/oauth/grant", :authorization=>authorization
|
51
|
+
code = Rack::Utils.parse_query(URI.parse(last_response["Location"]).query)["code"]
|
52
|
+
# Get access token
|
53
|
+
basic_authorize client.id, client.secret
|
54
|
+
post "/oauth/access_token", :scope=>"read write", :grant_type=>"authorization_code", :code=>code, :redirect_uri=>client.redirect_uri
|
55
|
+
@token = JSON.parse(last_response.body)["access_token"]
|
56
|
+
header "Authorization", nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def with_token(token = @token)
|
60
|
+
header "Authorization", "OAuth #{token}"
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# 5. Accessing a Protected Resource
|
65
|
+
|
66
|
+
context "public resource" do
|
67
|
+
context "no authorization" do
|
68
|
+
setup { get "/public" }
|
69
|
+
should_return_resource "HAI"
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with authorization" do
|
73
|
+
setup do
|
74
|
+
with_token
|
75
|
+
get "/public"
|
76
|
+
end
|
77
|
+
should_return_resource "HAI from Batman"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "private resource" do
|
82
|
+
context "no authorization" do
|
83
|
+
setup { get "/private" }
|
84
|
+
should_fail_authentication
|
85
|
+
end
|
86
|
+
|
87
|
+
context "HTTP authentication" do
|
88
|
+
context "valid token" do
|
89
|
+
setup do
|
90
|
+
with_token
|
91
|
+
get "/private"
|
92
|
+
end
|
93
|
+
should_return_resource "Shhhh"
|
94
|
+
end
|
95
|
+
|
96
|
+
context "unknown token" do
|
97
|
+
setup do
|
98
|
+
with_token "dingdong"
|
99
|
+
get "/private"
|
100
|
+
end
|
101
|
+
should_fail_authentication :invalid_token
|
102
|
+
end
|
103
|
+
|
104
|
+
context "revoked HTTP token" do
|
105
|
+
setup do
|
106
|
+
Server::AccessToken.from_token(@token).revoke!
|
107
|
+
with_token
|
108
|
+
get "/private"
|
109
|
+
end
|
110
|
+
should_fail_authentication :invalid_token
|
111
|
+
end
|
112
|
+
|
113
|
+
context "revoked client" do
|
114
|
+
setup do
|
115
|
+
client.revoke!
|
116
|
+
with_token
|
117
|
+
get "/private"
|
118
|
+
end
|
119
|
+
should_fail_authentication :invalid_token
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# 5.1.2. URI Query Parameter
|
124
|
+
|
125
|
+
context "query parameter" do
|
126
|
+
context "default mode" do
|
127
|
+
setup { get "/private?oauth_token=#{@token}" }
|
128
|
+
should_fail_authentication
|
129
|
+
end
|
130
|
+
|
131
|
+
context "enabled" do
|
132
|
+
setup do
|
133
|
+
config.param_authentication = true
|
134
|
+
end
|
135
|
+
|
136
|
+
context "valid token" do
|
137
|
+
setup { get "/private?oauth_token=#{@token}" }
|
138
|
+
should_return_resource "Shhhh"
|
139
|
+
end
|
140
|
+
|
141
|
+
context "invalid token" do
|
142
|
+
setup { get "/private?oauth_token=dingdong" }
|
143
|
+
should_fail_authentication :invalid_token
|
144
|
+
end
|
145
|
+
|
146
|
+
teardown do
|
147
|
+
config.param_authentication = false
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "POST" do
|
154
|
+
context "no authorization" do
|
155
|
+
setup { post "/change" }
|
156
|
+
should_fail_authentication
|
157
|
+
end
|
158
|
+
|
159
|
+
context "HTTP authentication" do
|
160
|
+
context "valid token" do
|
161
|
+
setup do
|
162
|
+
with_token
|
163
|
+
post "/change"
|
164
|
+
end
|
165
|
+
should_return_resource "Woot!"
|
166
|
+
end
|
167
|
+
|
168
|
+
context "unknown token" do
|
169
|
+
setup do
|
170
|
+
with_token "dingdong"
|
171
|
+
post "/change"
|
172
|
+
end
|
173
|
+
should_fail_authentication :invalid_token
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
# 5.1.3. Form-Encoded Body Parameter
|
179
|
+
|
180
|
+
context "body parameter" do
|
181
|
+
context "default mode" do
|
182
|
+
setup { post "/change", :oauth_token=>@token }
|
183
|
+
should_fail_authentication
|
184
|
+
end
|
185
|
+
|
186
|
+
context "enabled" do
|
187
|
+
setup do
|
188
|
+
config.param_authentication = true
|
189
|
+
end
|
190
|
+
|
191
|
+
context "valid token" do
|
192
|
+
setup { post "/change", :oauth_token=>@token }
|
193
|
+
should_return_resource "Woot!"
|
194
|
+
end
|
195
|
+
|
196
|
+
context "invalid token" do
|
197
|
+
setup { post "/change", :oauth_token=>"dingdong" }
|
198
|
+
should_fail_authentication :invalid_token
|
199
|
+
end
|
200
|
+
|
201
|
+
teardown do
|
202
|
+
config.param_authentication = false
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
context "insufficient scope" do
|
210
|
+
context "valid token" do
|
211
|
+
setup do
|
212
|
+
with_token
|
213
|
+
get "/calc"
|
214
|
+
end
|
215
|
+
|
216
|
+
should "respond with status 403 (Forbidden)" do
|
217
|
+
assert_equal 403, last_response.status
|
218
|
+
end
|
219
|
+
should "respond with authentication method OAuth" do
|
220
|
+
assert_equal "OAuth", last_response["WWW-Authenticate"].split.first
|
221
|
+
end
|
222
|
+
should "respond with realm" do
|
223
|
+
assert_match " realm=\"example.org\"", last_response["WWW-Authenticate"]
|
224
|
+
end
|
225
|
+
should "respond with error code insufficient_scope" do
|
226
|
+
assert_match " error=\"insufficient_scope\"", last_response["WWW-Authenticate"]
|
227
|
+
end
|
228
|
+
should "respond with scope name" do
|
229
|
+
assert_match " scope=\"math\"", last_response["WWW-Authenticate"]
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
context "setting resource" do
|
236
|
+
context "authenticated" do
|
237
|
+
setup do
|
238
|
+
with_token
|
239
|
+
get "/user"
|
240
|
+
end
|
241
|
+
|
242
|
+
should "render user name" do
|
243
|
+
assert_equal "Batman", last_response.body
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
context "not authenticated" do
|
248
|
+
setup do
|
249
|
+
get "/user"
|
250
|
+
end
|
251
|
+
|
252
|
+
should "not render user name" do
|
253
|
+
assert last_response.body.empty?
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
context "list tokens" do
|
259
|
+
setup do
|
260
|
+
@other = Server.token_for("foobar", client.id, "read")
|
261
|
+
get "/list_tokens"
|
262
|
+
end
|
263
|
+
|
264
|
+
should "return access token" do
|
265
|
+
assert_contains last_response.body.split, @token
|
266
|
+
end
|
267
|
+
|
268
|
+
should "not return other resource's token" do
|
269
|
+
assert !last_response.body.split.include?(@other)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
context "with specific host" do
|
275
|
+
context "right host" do
|
276
|
+
setup do
|
277
|
+
get "http://example.org/public"
|
278
|
+
end
|
279
|
+
# Right host, but not authenticated
|
280
|
+
should_return_resource "HAI"
|
281
|
+
end
|
282
|
+
|
283
|
+
context "wrong host" do
|
284
|
+
setup do
|
285
|
+
with_token
|
286
|
+
get "http://wrong.org/public"
|
287
|
+
end
|
288
|
+
# Wrong host, not checking credentials
|
289
|
+
should_return_resource "HAI"
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
context "with specific path" do
|
295
|
+
setup { config.path = "/private" }
|
296
|
+
|
297
|
+
context "outside path" do
|
298
|
+
setup { with_token ; get "http://example.org/public" }
|
299
|
+
# Not authenticated
|
300
|
+
should_return_resource "HAI"
|
301
|
+
end
|
302
|
+
|
303
|
+
context "inside path" do
|
304
|
+
setup { with_token ; get "http://example.org/private" }
|
305
|
+
# Authenticated
|
306
|
+
should_return_resource "Shhhh"
|
307
|
+
end
|
308
|
+
|
309
|
+
teardown { config.path = nil }
|
310
|
+
end
|
311
|
+
end
|