doorkeeper 0.3.0 → 0.4.0
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/.gitignore +12 -0
- data/.rspec +1 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +98 -0
- data/Gemfile +6 -0
- data/README.md +42 -6
- data/app/controllers/doorkeeper/application_controller.rb +4 -11
- data/app/controllers/doorkeeper/applications_controller.rb +7 -1
- data/app/controllers/doorkeeper/authorizations_controller.rb +11 -1
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +3 -3
- data/app/controllers/doorkeeper/tokens_controller.rb +19 -5
- data/app/models/doorkeeper/access_grant.rb +28 -0
- data/app/models/doorkeeper/access_token.rb +65 -0
- data/app/models/doorkeeper/application.rb +54 -0
- data/app/views/doorkeeper/applications/index.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +15 -15
- data/app/views/doorkeeper/authorized_applications/index.html.erb +1 -2
- data/config/locales/en.yml +3 -0
- data/doorkeeper.gemspec +28 -0
- data/gemfiles/gemfile.rails-3.1.x +7 -0
- data/gemfiles/gemfile.rails-3.2.x +7 -0
- data/lib/doorkeeper/config.rb +73 -12
- data/lib/doorkeeper/doorkeeper_for.rb +19 -15
- data/lib/doorkeeper/engine.rb +28 -0
- data/lib/doorkeeper/models/scopes.rb +13 -0
- data/lib/doorkeeper/oauth/access_token_request.rb +9 -20
- data/lib/doorkeeper/oauth/authorization/code.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/token.rb +2 -2
- data/lib/doorkeeper/oauth/authorization_request.rb +18 -23
- data/lib/doorkeeper/oauth/client/credentials.rb +21 -0
- data/lib/doorkeeper/oauth/client/methods.rb +18 -0
- data/lib/doorkeeper/oauth/client.rb +27 -0
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +29 -0
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +35 -0
- data/lib/doorkeeper/oauth/client_credentials/response.rb +42 -0
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +33 -0
- data/lib/doorkeeper/oauth/client_credentials_request.rb +46 -0
- data/lib/doorkeeper/oauth/error.rb +9 -0
- data/lib/doorkeeper/oauth/error_response.rb +30 -0
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -2
- data/lib/doorkeeper/oauth/password_access_token_request.rb +130 -0
- data/lib/doorkeeper/oauth/scopes.rb +60 -0
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/doorkeeper.rb +23 -3
- data/lib/generators/doorkeeper/install_generator.rb +1 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +12 -7
- data/lib/generators/doorkeeper/templates/migration.rb +1 -1
- data/lib/generators/doorkeeper/views_generator.rb +15 -0
- data/script/rails +6 -0
- data/script/run_all +11 -0
- data/spec/controllers/applications_controller_spec.rb +18 -0
- data/spec/controllers/authorizations_controller_spec.rb +131 -0
- data/spec/controllers/protected_resources_controller_spec.rb +308 -0
- data/spec/controllers/tokens_controller_spec.rb +34 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +12 -0
- data/spec/dummy/app/controllers/home_controller.rb +17 -0
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +11 -0
- data/spec/dummy/app/helpers/application_helper.rb +5 -0
- data/spec/dummy/app/models/user.rb +11 -0
- data/spec/dummy/app/views/home/index.html.erb +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +16 -0
- data/spec/dummy/config/application.rb +53 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +15 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +30 -0
- data/spec/dummy/config/environments/production.rb +60 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +41 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/doorkeeper.en.yml +5 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +9 -0
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +5 -0
- data/spec/dummy/db/migrate/20120524202412_create_doorkeeper_tables.rb +42 -0
- data/spec/dummy/db/schema.rb +62 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/access_grant.rb +9 -0
- data/spec/factories/access_token.rb +7 -0
- data/spec/factories/application.rb +6 -0
- data/spec/generators/install_generator_spec.rb +35 -0
- data/spec/generators/templates/routes.rb +3 -0
- data/spec/generators/views_generator_spec.rb +27 -0
- data/spec/lib/config_spec.rb +87 -0
- data/spec/lib/models/expirable_spec.rb +49 -0
- data/spec/lib/models/revocable_spec.rb +31 -0
- data/spec/lib/models/scopes_spec.rb +32 -0
- data/spec/lib/oauth/access_token_request_spec.rb +240 -0
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +37 -0
- data/spec/lib/oauth/authorization_request_spec.rb +286 -0
- data/spec/lib/oauth/client/credentials_spec.rb +47 -0
- data/spec/lib/oauth/client/methods_spec.rb +54 -0
- data/spec/lib/oauth/client_credentials/creator_spec.rb +47 -0
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +57 -0
- data/spec/lib/oauth/client_credentials/response_spec.rb +58 -0
- data/spec/lib/oauth/client_credentials/validation_spec.rb +29 -0
- data/spec/lib/oauth/client_credentials_integration_spec.rb +27 -0
- data/spec/lib/oauth/client_credentials_request_spec.rb +60 -0
- data/spec/lib/oauth/client_spec.rb +42 -0
- data/spec/lib/oauth/error_response_spec.rb +40 -0
- data/spec/lib/oauth/error_spec.rb +19 -0
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +74 -0
- data/spec/lib/oauth/helpers/unique_token_spec.rb +38 -0
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +64 -0
- data/spec/lib/oauth/password_access_token_request_spec.rb +152 -0
- data/spec/lib/oauth/scopes_spec.rb +115 -0
- data/spec/models/doorkeeper/access_grant_spec.rb +36 -0
- data/spec/models/doorkeeper/access_token_spec.rb +113 -0
- data/spec/models/doorkeeper/application_spec.rb +129 -0
- data/spec/requests/applications/applications_request_spec.rb +92 -0
- data/spec/requests/applications/authorized_applications_spec.rb +30 -0
- data/spec/requests/endpoints/authorization_spec.rb +63 -0
- data/spec/requests/endpoints/token_spec.rb +29 -0
- data/spec/requests/flows/authorization_code_errors_spec.rb +111 -0
- data/spec/requests/flows/authorization_code_spec.rb +125 -0
- data/spec/requests/flows/client_credentials_spec.rb +56 -0
- data/spec/requests/flows/implicit_grant_errors_spec.rb +31 -0
- data/spec/requests/flows/implicit_grant_spec.rb +19 -0
- data/spec/requests/flows/password_spec.rb +52 -0
- data/spec/requests/flows/refresh_token_spec.rb +66 -0
- data/spec/requests/flows/skip_authorization_spec.rb +40 -0
- data/spec/requests/protected_resources/private_api_spec.rb +43 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/spec_helper_integration.rb +28 -0
- data/spec/support/dependencies/database_cleaner.rb +16 -0
- data/spec/support/dependencies/factory_girl.rb +5 -0
- data/spec/support/helpers/access_token_request_helper.rb +11 -0
- data/spec/support/helpers/authorization_request_helper.rb +32 -0
- data/spec/support/helpers/config_helper.rb +9 -0
- data/spec/support/helpers/model_helper.rb +45 -0
- data/spec/support/helpers/request_spec_helper.rb +72 -0
- data/spec/support/helpers/url_helper.rb +51 -0
- data/spec/support/shared/controllers_shared_context.rb +60 -0
- data/spec/support/shared/models_shared_examples.rb +44 -0
- metadata +163 -57
- data/app/controllers/doorkeeper/application_controller.rbc +0 -675
- data/app/controllers/doorkeeper/applications_controller.rbc +0 -954
- data/app/controllers/doorkeeper/authorizations_controller.rbc +0 -659
- data/app/controllers/doorkeeper/authorized_applications_controller.rbc +0 -393
- data/app/controllers/doorkeeper/tokens_controller.rbc +0 -423
- data/app/helpers/doorkeeper/application_helper.rbc +0 -127
- data/app/models/access_grant.rb +0 -31
- data/app/models/access_grant.rbc +0 -821
- data/app/models/access_token.rb +0 -70
- data/app/models/access_token.rbc +0 -979
- data/app/models/application.rb +0 -45
- data/app/models/application.rbc +0 -753
- data/config/initializers/form_errors.rbc +0 -272
- data/config/routes.rbc +0 -366
- data/lib/doorkeeper/config/scope.rb +0 -11
- data/lib/doorkeeper/config/scopes.rb +0 -61
- data/lib/doorkeeper/config/scopes_builder.rb +0 -18
- data/lib/doorkeeper/config.rbc +0 -1385
- data/lib/doorkeeper/doorkeeper_for.rbc +0 -1029
- data/lib/doorkeeper/engine.rbc +0 -318
- data/lib/doorkeeper/oauth/access_token_request.rbc +0 -2042
- data/lib/doorkeeper/oauth/authorization_request.rbc +0 -2272
- data/lib/doorkeeper/oauth/random_string.rbc +0 -437
- data/lib/doorkeeper/validations.rbc +0 -774
- data/lib/doorkeeper/version.rbc +0 -130
- data/lib/doorkeeper.rbc +0 -407
- data/lib/generators/doorkeeper/install_generator.rbc +0 -453
- data/lib/tasks/doorkeeper_tasks.rake.compiled.rbc +0 -40
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
require 'spec_helper_integration'
|
|
2
|
+
|
|
3
|
+
module Doorkeeper::OAuth
|
|
4
|
+
describe AccessTokenRequest do
|
|
5
|
+
let(:client) { FactoryGirl.create(:application) }
|
|
6
|
+
let(:grant) { FactoryGirl.create(:access_grant, :application => client) }
|
|
7
|
+
let(:params) {
|
|
8
|
+
{
|
|
9
|
+
:code => grant.token,
|
|
10
|
+
:grant_type => "authorization_code",
|
|
11
|
+
:redirect_uri => client.redirect_uri
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe "with a valid authorization code and client" do
|
|
16
|
+
subject { AccessTokenRequest.new(client, params) }
|
|
17
|
+
|
|
18
|
+
before { subject.authorize }
|
|
19
|
+
|
|
20
|
+
it { should be_valid }
|
|
21
|
+
its(:token_type) { should == "bearer" }
|
|
22
|
+
its(:error) { should be_nil }
|
|
23
|
+
its(:refresh_token) { should be_nil }
|
|
24
|
+
|
|
25
|
+
it "has an access token" do
|
|
26
|
+
subject.access_token.token.should =~ /\w+/
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "creating the access token" do
|
|
31
|
+
subject { AccessTokenRequest.new(client, params) }
|
|
32
|
+
|
|
33
|
+
it "creates with correct params" do
|
|
34
|
+
Doorkeeper::AccessToken.should_receive(:create!).with({
|
|
35
|
+
:application_id => client.id,
|
|
36
|
+
:resource_owner_id => grant.resource_owner_id,
|
|
37
|
+
:expires_in => 2.hours,
|
|
38
|
+
:scopes =>"public write",
|
|
39
|
+
:use_refresh_token => false,
|
|
40
|
+
})
|
|
41
|
+
subject.authorize
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe "with a valid authorization code, client and existing valid access token" do
|
|
46
|
+
subject { AccessTokenRequest.new(client, params) }
|
|
47
|
+
|
|
48
|
+
before { subject.authorize }
|
|
49
|
+
it { should be_valid }
|
|
50
|
+
its(:error) { should be_nil }
|
|
51
|
+
|
|
52
|
+
it "will not create a new token" do
|
|
53
|
+
subject.should_not_receive(:create_access_token)
|
|
54
|
+
subject.authorize
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe "with a valid authorization code, client and existing expired access token" do
|
|
59
|
+
subject { AccessTokenRequest.new(client, params) }
|
|
60
|
+
|
|
61
|
+
it "will create a new token" do
|
|
62
|
+
subject.authorize
|
|
63
|
+
expired_access_token = subject.access_token.dup
|
|
64
|
+
subject.access_token.created_at = Time.now - subject.access_token.expires_in - 1.second
|
|
65
|
+
subject.should_receive(:create_access_token)
|
|
66
|
+
subject.access_token.should_receive(:revoke)
|
|
67
|
+
subject.authorize
|
|
68
|
+
subject.access_token.should_not eq(expired_access_token)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe "finding the current access token" do
|
|
73
|
+
subject { AccessTokenRequest.new(client, params) }
|
|
74
|
+
it { should be_valid }
|
|
75
|
+
its(:error) { should be_nil }
|
|
76
|
+
|
|
77
|
+
before { subject.authorize }
|
|
78
|
+
|
|
79
|
+
it "should find the access token and not create a new one" do
|
|
80
|
+
subject.should_not_receive(:create_access_token)
|
|
81
|
+
access_token = subject.authorize
|
|
82
|
+
subject.access_token.should eq(access_token)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe "creating the first access_token" do
|
|
87
|
+
subject { AccessTokenRequest.new(client, params) }
|
|
88
|
+
it { should be_valid }
|
|
89
|
+
its(:error) { should be_nil }
|
|
90
|
+
|
|
91
|
+
it "should create a new access token" do
|
|
92
|
+
subject.should_receive(:create_access_token)
|
|
93
|
+
subject.authorize
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe "with errors" do
|
|
98
|
+
def token(params)
|
|
99
|
+
AccessTokenRequest.new(client, params)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "includes the error in the response" do
|
|
103
|
+
access_token = token(params.except(:grant_type))
|
|
104
|
+
access_token.error_response.name.should == :invalid_request
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
[:grant_type, :code, :redirect_uri].each do |param|
|
|
108
|
+
describe "when :#{param} is missing" do
|
|
109
|
+
subject { token(params.except(param)) }
|
|
110
|
+
its(:error) { should == :invalid_request }
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe "when client is not present" do
|
|
115
|
+
subject { AccessTokenRequest.new(nil, params) }
|
|
116
|
+
its(:error) { should == :invalid_client }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe "when :code does not exist" do
|
|
120
|
+
subject { token(params.merge(:code => "inexistent")) }
|
|
121
|
+
its(:error) { should == :invalid_grant }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe "when :redirect_uri does not match with grant's one" do
|
|
125
|
+
subject { token(params.merge(:redirect_uri => "another")) }
|
|
126
|
+
its(:error) { should == :invalid_grant }
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
describe "when :grant_type is not 'authorization_code'" do
|
|
130
|
+
subject { token(params.merge(:grant_type => "invalid")) }
|
|
131
|
+
its(:error) { should == :unsupported_grant_type }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe "when granted application does not match" do
|
|
135
|
+
subject { token(params) }
|
|
136
|
+
|
|
137
|
+
before do
|
|
138
|
+
grant.application = FactoryGirl.create(:application)
|
|
139
|
+
grant.save!
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
its(:error) { should == :invalid_grant }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe "when :code is expired" do
|
|
146
|
+
it "error is :invalid_grant" do
|
|
147
|
+
grant # create grant instance
|
|
148
|
+
Timecop.freeze(Time.now + 700.seconds) do
|
|
149
|
+
expired = token(params)
|
|
150
|
+
expired.error.should == :invalid_grant
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
describe AccessTokenRequest, "refresh token" do
|
|
158
|
+
let(:client) { FactoryGirl.create(:application) }
|
|
159
|
+
let(:access) { FactoryGirl.create(:access_token, :application => client, :use_refresh_token => true) }
|
|
160
|
+
let(:params) {
|
|
161
|
+
{
|
|
162
|
+
:refresh_token => access.refresh_token,
|
|
163
|
+
:grant_type => "refresh_token",
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
before do
|
|
168
|
+
Doorkeeper.configure { use_refresh_token }
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
describe "with a valid authorization code and client" do
|
|
172
|
+
subject { AccessTokenRequest.new(client, params) }
|
|
173
|
+
|
|
174
|
+
before do
|
|
175
|
+
subject.authorize
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it { should be_valid }
|
|
179
|
+
its(:token_type) { should == "bearer" }
|
|
180
|
+
its(:error) { should be_nil }
|
|
181
|
+
its(:refresh_token) { should_not be_nil }
|
|
182
|
+
|
|
183
|
+
it "has an access token" do
|
|
184
|
+
subject.access_token.token.should =~ /\w+/
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
describe "with errors" do
|
|
189
|
+
def token(params)
|
|
190
|
+
AccessTokenRequest.new(client, params)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it "includes the error in the response" do
|
|
194
|
+
access_token = token(params.except(:grant_type))
|
|
195
|
+
access_token.error_response.name.should == :invalid_request
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
[:grant_type, :refresh_token].each do |param|
|
|
199
|
+
describe "when :#{param} is missing" do
|
|
200
|
+
subject { token(params.except(param)) }
|
|
201
|
+
its(:error) { should == :invalid_request }
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
describe "when client is not present" do
|
|
206
|
+
subject { AccessTokenRequest.new(nil, params) }
|
|
207
|
+
its(:error) { should == :invalid_client }
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
describe "when :refresh_token does not exist" do
|
|
211
|
+
subject { token(params.merge(:refresh_token => "inexistent")) }
|
|
212
|
+
its(:error) { should == :invalid_grant }
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
describe "when :grant_type is not 'refresh_token'" do
|
|
216
|
+
subject { token(params.merge(:grant_type => "invalid")) }
|
|
217
|
+
its(:error) { should == :invalid_request }
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
describe "when granted application does not match" do
|
|
221
|
+
subject { token(params) }
|
|
222
|
+
|
|
223
|
+
before do
|
|
224
|
+
access.application = FactoryGirl.create(:application)
|
|
225
|
+
access.save!
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
its(:error) { should == :invalid_grant }
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
describe "when :refresh_token is revoked" do
|
|
232
|
+
it "error is :invalid_grant" do
|
|
233
|
+
access.revoke # create grant instance
|
|
234
|
+
revoked = token(params)
|
|
235
|
+
revoked.error.should == :invalid_grant
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'active_support/core_ext/string'
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'rack/utils'
|
|
5
|
+
require 'doorkeeper/oauth/authorization/uri_builder'
|
|
6
|
+
|
|
7
|
+
module Doorkeeper::OAuth::Authorization
|
|
8
|
+
describe URIBuilder do
|
|
9
|
+
|
|
10
|
+
subject { Object.new.class.send :include, URIBuilder }
|
|
11
|
+
|
|
12
|
+
describe :uri_with_query do
|
|
13
|
+
it 'returns the uri with query' do
|
|
14
|
+
uri = subject.uri_with_query 'http://example.com/', :parameter => 'value'
|
|
15
|
+
uri.should == 'http://example.com/?parameter=value'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'rejects nil values' do
|
|
19
|
+
uri = subject.uri_with_query 'http://example.com/', :parameter => ""
|
|
20
|
+
uri.should == 'http://example.com/?'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'preserves original query parameters' do
|
|
24
|
+
uri = subject.uri_with_query 'http://example.com/?query1=value', :parameter => 'value'
|
|
25
|
+
uri.should =~ /query1=value/
|
|
26
|
+
uri.should =~ /parameter=value/
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe :uri_with_fragment do
|
|
31
|
+
it 'returns uri with parameters as fragments' do
|
|
32
|
+
uri = subject.uri_with_fragment 'http://example.com/', :parameter => 'value'
|
|
33
|
+
uri.should == 'http://example.com/#parameter=value'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
require 'spec_helper_integration'
|
|
2
|
+
|
|
3
|
+
module Doorkeeper::OAuth
|
|
4
|
+
describe AuthorizationRequest do
|
|
5
|
+
let(:resource_owner) { double(:resource_owner, :id => 1) }
|
|
6
|
+
let(:client) { FactoryGirl.create(:application) }
|
|
7
|
+
let(:base_attributes) do
|
|
8
|
+
{
|
|
9
|
+
:redirect_uri => client.redirect_uri,
|
|
10
|
+
:scope => "public write",
|
|
11
|
+
:state => "return-this"
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
before :each do
|
|
16
|
+
Doorkeeper.configuration.stub(:default_scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('public write'))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "with a code response_type" do
|
|
20
|
+
let(:attributes) { base_attributes.merge!(:response_type => "code") }
|
|
21
|
+
|
|
22
|
+
describe "with valid attributes" do
|
|
23
|
+
subject { AuthorizationRequest.new(client, resource_owner, attributes) }
|
|
24
|
+
|
|
25
|
+
describe "after authorization" do
|
|
26
|
+
before { subject.authorize }
|
|
27
|
+
|
|
28
|
+
its(:response_type) { should == "code" }
|
|
29
|
+
its(:client_id) { should == client.uid }
|
|
30
|
+
its(:scope) { should == "public write" }
|
|
31
|
+
its(:state) { should == "return-this" }
|
|
32
|
+
its(:error) { should be_nil }
|
|
33
|
+
|
|
34
|
+
describe ".success_redirect_uri" do
|
|
35
|
+
let(:query) { URI.parse(subject.success_redirect_uri).query }
|
|
36
|
+
|
|
37
|
+
it "includes the grant code" do
|
|
38
|
+
query.should =~ %r{code=\w+}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "includes the state previous assumed" do
|
|
42
|
+
query.should =~ %r{state=return-this}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe :authorize do
|
|
48
|
+
let(:authorization_request) { AuthorizationRequest.new(client, resource_owner, attributes) }
|
|
49
|
+
subject { authorization_request.authorize }
|
|
50
|
+
|
|
51
|
+
it "returns Doorkeeper::AccessGrant object" do
|
|
52
|
+
subject.is_a? Doorkeeper::AccessGrant
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "returns instance saved in the database" do
|
|
56
|
+
subject.should be_persisted
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "returns object that has scopes attribute same as scope attribute of authorization request" do
|
|
60
|
+
subject.scopes == authorization_request.scope
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "with a redirect_uri with query params" do
|
|
66
|
+
let(:original_query_params) { "abc=123&def=456" }
|
|
67
|
+
let(:attributes_with_query_params) {
|
|
68
|
+
u = URI.parse(client.redirect_uri)
|
|
69
|
+
u.query = original_query_params
|
|
70
|
+
attributes[:redirect_uri] = u.to_s
|
|
71
|
+
attributes
|
|
72
|
+
}
|
|
73
|
+
subject { AuthorizationRequest.new(client, resource_owner, attributes_with_query_params) }
|
|
74
|
+
|
|
75
|
+
it "preservers the original query when error"
|
|
76
|
+
|
|
77
|
+
describe "after authorization" do
|
|
78
|
+
before { subject.authorize }
|
|
79
|
+
|
|
80
|
+
describe ".success_redirect_uri" do
|
|
81
|
+
let(:query) { URI.parse(subject.success_redirect_uri).query }
|
|
82
|
+
|
|
83
|
+
it "includes the grant code" do
|
|
84
|
+
query.should =~ %r{code=\w+}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "includes the state previous assumed" do
|
|
88
|
+
query.should =~ %r{state=return-this}
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "preserves the original query parameters" do
|
|
92
|
+
query.should =~ /abc=123/
|
|
93
|
+
query.should =~ /def=456/
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
describe "if no scope given" do
|
|
100
|
+
it "sets the scope to the default one" do
|
|
101
|
+
request = AuthorizationRequest.new(client, resource_owner, attributes.except(:scope))
|
|
102
|
+
request.scopes.to_s.should == "public write"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe "with errors" do
|
|
107
|
+
before do
|
|
108
|
+
Doorkeeper::AccessGrant.should_not_receive(:create)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
describe "when :response_type is missing" do
|
|
112
|
+
subject { auth(attributes.except(:response_type)) }
|
|
113
|
+
its(:error) { should == :invalid_request }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe "when :redirect_uri is missing" do
|
|
117
|
+
subject { auth(attributes.except(:redirect_uri)) }
|
|
118
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
describe "when client is not present" do
|
|
122
|
+
subject { AuthorizationRequest.new(nil, resource_owner, attributes) }
|
|
123
|
+
its(:error) { should == :invalid_client }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
describe "when :redirect_uri mismatches" do
|
|
127
|
+
subject { auth(attributes.merge(:redirect_uri => "http://example.com/mismatch")) }
|
|
128
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe "when :redirect_uri contains a fragment" do
|
|
132
|
+
subject { auth(attributes.merge(:redirect_uri => (client.redirect_uri + "#abc"))) }
|
|
133
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
describe "when :redirect_uri is not a valid URI" do
|
|
137
|
+
subject { auth(attributes.merge(:redirect_uri => "invalid")) }
|
|
138
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe "when :response_type is not 'code' or 'token'" do
|
|
142
|
+
subject { auth(attributes.merge(:response_type => "invalid")) }
|
|
143
|
+
its(:error) { should == :unsupported_response_type }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
describe "when :scope contains scopes that are note registered in the provider" do
|
|
147
|
+
subject { auth(attributes.merge(:scope => "public strange")) }
|
|
148
|
+
its(:error) { should == :invalid_scope }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
describe "with a token response_type" do
|
|
154
|
+
before do
|
|
155
|
+
Doorkeeper.configuration.stub(:access_token_expires_in).and_return(7200)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
let(:attributes) { base_attributes.merge!(:response_type => "token") }
|
|
159
|
+
|
|
160
|
+
describe "with valid attributes" do
|
|
161
|
+
subject { AuthorizationRequest.new(client, resource_owner, attributes) }
|
|
162
|
+
|
|
163
|
+
describe "after authorization" do
|
|
164
|
+
before { subject.authorize }
|
|
165
|
+
|
|
166
|
+
its(:response_type) { should == "token" }
|
|
167
|
+
its(:scope) { should == "public write" }
|
|
168
|
+
its(:state) { should == "return-this" }
|
|
169
|
+
its(:error) { should be_nil }
|
|
170
|
+
|
|
171
|
+
describe ".success_redirect_uri" do
|
|
172
|
+
let(:fragment) { URI.parse(subject.success_redirect_uri).fragment }
|
|
173
|
+
|
|
174
|
+
it "has a fragment" do
|
|
175
|
+
fragment.should_not be_nil
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it "doesn't have query parameters" do
|
|
179
|
+
URI.parse(subject.success_redirect_uri).query.should be_nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it "includes the access token" do
|
|
183
|
+
fragment.should =~ %r{access_token=\w+}
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "includes the token type" do
|
|
187
|
+
fragment.should =~ %r{token_type=bearer}
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "includes the expires in" do
|
|
191
|
+
fragment.should =~ %r{expires_in=\w+}
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it "includes the state previous assumed" do
|
|
195
|
+
fragment.should =~ %r{state=return-this}
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
describe :authorize do
|
|
201
|
+
let(:authorization_request) { AuthorizationRequest.new(client, resource_owner, attributes) }
|
|
202
|
+
subject { authorization_request.authorize }
|
|
203
|
+
|
|
204
|
+
it "returns Doorkeeper::AccessGrant object" do
|
|
205
|
+
subject.is_a? Doorkeeper::AccessGrant
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it "returns instance saved in the database" do
|
|
209
|
+
subject.should be_persisted
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "returns object that has scopes attribute same as scope attribute of authorization request" do
|
|
213
|
+
subject.scopes == authorization_request.scope
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
describe "if no scope given" do
|
|
219
|
+
it "sets the scope to the default one" do
|
|
220
|
+
request = AuthorizationRequest.new(client, resource_owner, attributes.except(:scope))
|
|
221
|
+
request.scopes.to_s.should == "public write"
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe "with errors" do
|
|
226
|
+
before do
|
|
227
|
+
Doorkeeper::AccessGrant.should_not_receive(:create)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
describe "when :response_type is missing" do
|
|
231
|
+
subject { auth(attributes.except(:response_type)) }
|
|
232
|
+
its(:error) { should == :invalid_request }
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
describe "when :redirect_uri is missing" do
|
|
236
|
+
subject { auth(attributes.except(:redirect_uri)) }
|
|
237
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
describe "when client is not present" do
|
|
241
|
+
subject { AuthorizationRequest.new(nil, resource_owner, attributes) }
|
|
242
|
+
its(:error) { should == :invalid_client }
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
describe "when :redirect_uri has a fragment" do
|
|
246
|
+
subject { auth(attributes.merge(:redirect_uri => client.redirect_uri + "#xyz")) }
|
|
247
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
describe "when :redirect_uri is a relative URI" do
|
|
251
|
+
subject { auth(attributes.merge(:redirect_uri => "/abcdef")) }
|
|
252
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
describe "when :redirect_uri mismatches" do
|
|
256
|
+
subject { auth(attributes.merge(:redirect_uri => "http://example.com/mismatch")) }
|
|
257
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
describe "when :redirect_uri contains a fragment" do
|
|
261
|
+
subject { auth(attributes.merge(:redirect_uri => (client.redirect_uri + "#abc"))) }
|
|
262
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
describe "when :redirect_uri is not a valid URI" do
|
|
266
|
+
subject { auth(attributes.merge(:redirect_uri => "invalid")) }
|
|
267
|
+
its(:error) { should == :invalid_redirect_uri }
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
describe "when :response_type is not 'code' or 'token'" do
|
|
271
|
+
subject { auth(attributes.merge(:response_type => "invalid")) }
|
|
272
|
+
its(:error) { should == :unsupported_response_type }
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
describe "when :scope contains scopes that are note registered in the provider" do
|
|
276
|
+
subject { auth(attributes.merge(:scope => "public strange")) }
|
|
277
|
+
its(:error) { should == :invalid_scope }
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def auth(attributes)
|
|
283
|
+
AuthorizationRequest.new(client, resource_owner, attributes)
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'active_support/core_ext/string'
|
|
3
|
+
require 'doorkeeper/oauth/client'
|
|
4
|
+
|
|
5
|
+
class Doorkeeper::OAuth::Client
|
|
6
|
+
describe Credentials do
|
|
7
|
+
it 'is blank when any of the credentials is blank' do
|
|
8
|
+
Credentials.new(nil, "something").should be_blank
|
|
9
|
+
Credentials.new("something", nil).should be_blank
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe :from_request do
|
|
13
|
+
let(:request) { stub.as_null_object }
|
|
14
|
+
|
|
15
|
+
let(:method) do
|
|
16
|
+
lambda { |request| return 'uid', 'secret' }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'accepts anything that responds to #call' do
|
|
20
|
+
method.should_receive(:call).with(request)
|
|
21
|
+
Credentials.from_request request, method
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'delegates methods received as symbols to Credentials class' do
|
|
25
|
+
Credentials.should_receive(:from_params).with(request)
|
|
26
|
+
Credentials.from_request request, :from_params
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'stops at the first credentials found' do
|
|
30
|
+
not_called_method = mock
|
|
31
|
+
not_called_method.should_not_receive(:call)
|
|
32
|
+
credentials = Credentials.from_request request, lambda { |r| }, method, not_called_method
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'returns new Credentials' do
|
|
36
|
+
credentials = Credentials.from_request request, method
|
|
37
|
+
credentials.should be_a(Credentials)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'returns uid and secret from extractor method' do
|
|
41
|
+
credentials = Credentials.from_request request, method
|
|
42
|
+
credentials.uid.should == 'uid'
|
|
43
|
+
credentials.secret.should == 'secret'
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'active_support/core_ext/string'
|
|
3
|
+
require 'doorkeeper/oauth/client'
|
|
4
|
+
|
|
5
|
+
class Doorkeeper::OAuth::Client
|
|
6
|
+
describe 'Methods' do
|
|
7
|
+
let(:client_id) { "some-uid" }
|
|
8
|
+
let(:client_secret) { "some-secret" }
|
|
9
|
+
|
|
10
|
+
subject do
|
|
11
|
+
Class.new do
|
|
12
|
+
include Methods
|
|
13
|
+
end.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe :from_params do
|
|
17
|
+
it 'returns credentials from parameters when Authorization header is not available' do
|
|
18
|
+
request = stub :parameters => { :client_id => client_id, :client_secret => client_secret }
|
|
19
|
+
uid, secret = subject.from_params(request)
|
|
20
|
+
|
|
21
|
+
uid.should == "some-uid"
|
|
22
|
+
secret.should == "some-secret"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'is blank when there are no credentials' do
|
|
26
|
+
request = stub :parameters => {}
|
|
27
|
+
uid, secret = subject.from_params(request)
|
|
28
|
+
|
|
29
|
+
uid.should be_blank
|
|
30
|
+
secret.should be_blank
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe :from_basic do
|
|
35
|
+
let(:credentials) { Base64.encode64("#{client_id}:#{client_secret}") }
|
|
36
|
+
|
|
37
|
+
it 'decodes the credentials' do
|
|
38
|
+
request = stub :authorization => "Basic #{credentials}"
|
|
39
|
+
uid, secret = subject.from_basic(request)
|
|
40
|
+
|
|
41
|
+
uid.should == "some-uid"
|
|
42
|
+
secret.should == "some-secret"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'is blank if Authorization is not Basic' do
|
|
46
|
+
request = stub :authorization => "#{credentials}"
|
|
47
|
+
uid, secret = subject.from_basic(request)
|
|
48
|
+
|
|
49
|
+
uid.should be_blank
|
|
50
|
+
secret.should be_blank
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|