tpitale-rack-oauth2-server 2.2.1
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/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
|