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,152 @@
|
|
|
1
|
+
require 'spec_helper_integration'
|
|
2
|
+
|
|
3
|
+
module Doorkeeper::OAuth
|
|
4
|
+
describe PasswordAccessTokenRequest do
|
|
5
|
+
let(:client) { Factory(:application) }
|
|
6
|
+
let(:owner) { User.create!(:name => "Joe", :password => "sekret") }
|
|
7
|
+
let(:params) {
|
|
8
|
+
{
|
|
9
|
+
:grant_type => "password"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe "with a valid owner and client" do
|
|
14
|
+
subject { PasswordAccessTokenRequest.new(client, owner, params) }
|
|
15
|
+
|
|
16
|
+
before { subject.authorize }
|
|
17
|
+
|
|
18
|
+
it { should be_valid }
|
|
19
|
+
|
|
20
|
+
its(:token_type) { should == "bearer" }
|
|
21
|
+
its(:error) { should be_nil }
|
|
22
|
+
its(:refresh_token) { should be_nil }
|
|
23
|
+
|
|
24
|
+
it "has an access token" do
|
|
25
|
+
subject.access_token.token.should =~ /\w+/
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "with a valid client but an invalid owner" do
|
|
30
|
+
subject { PasswordAccessTokenRequest.new(client, nil, params) }
|
|
31
|
+
|
|
32
|
+
before { subject.authorize }
|
|
33
|
+
|
|
34
|
+
it { should_not be_valid }
|
|
35
|
+
its(:error) { should == :invalid_resource_owner }
|
|
36
|
+
its(:access_token) { should be_nil }
|
|
37
|
+
its(:refresh_token) { should be_nil }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe "with a valid owner but an invalid client" do
|
|
41
|
+
subject { PasswordAccessTokenRequest.new(nil, owner, params) }
|
|
42
|
+
|
|
43
|
+
before { subject.authorize }
|
|
44
|
+
|
|
45
|
+
it { should_not be_valid }
|
|
46
|
+
its(:error) { should == :invalid_client }
|
|
47
|
+
its(:access_token) { should be_nil }
|
|
48
|
+
its(:refresh_token) { should be_nil }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe "creating the access token" do
|
|
52
|
+
subject { PasswordAccessTokenRequest.new(client, owner, params) }
|
|
53
|
+
|
|
54
|
+
it "creates with correct params" do
|
|
55
|
+
Doorkeeper::AccessToken.should_receive(:create!).with({
|
|
56
|
+
:application_id => client.id,
|
|
57
|
+
:resource_owner_id => owner.id,
|
|
58
|
+
:expires_in => 2.hours,
|
|
59
|
+
:scopes =>"",
|
|
60
|
+
:use_refresh_token => false,
|
|
61
|
+
})
|
|
62
|
+
subject.authorize
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "creates a refresh token if Doorkeeper is configured to do so" do
|
|
66
|
+
Doorkeeper.configure { use_refresh_token }
|
|
67
|
+
|
|
68
|
+
Doorkeeper::AccessToken.should_receive(:create!).with({
|
|
69
|
+
:application_id => client.id,
|
|
70
|
+
:resource_owner_id => owner.id,
|
|
71
|
+
:expires_in => 2.hours,
|
|
72
|
+
:scopes =>"",
|
|
73
|
+
:use_refresh_token => true,
|
|
74
|
+
})
|
|
75
|
+
subject.authorize
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe "with an existing valid access token" do
|
|
80
|
+
subject { PasswordAccessTokenRequest.new(client, owner, params) }
|
|
81
|
+
|
|
82
|
+
before { subject.authorize }
|
|
83
|
+
it { should be_valid }
|
|
84
|
+
its(:error) { should be_nil }
|
|
85
|
+
|
|
86
|
+
it "will not create a new token" do
|
|
87
|
+
subject.should_not_receive(:create_access_token)
|
|
88
|
+
subject.authorize
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe "with an existing expired access token" do
|
|
93
|
+
subject { PasswordAccessTokenRequest.new(client, owner, params) }
|
|
94
|
+
|
|
95
|
+
it "will create a new token" do
|
|
96
|
+
subject.authorize
|
|
97
|
+
expired_access_token = subject.access_token.dup
|
|
98
|
+
subject.access_token.created_at = Time.now - subject.access_token.expires_in - 1.second
|
|
99
|
+
subject.should_receive(:create_access_token)
|
|
100
|
+
subject.access_token.should_receive(:revoke)
|
|
101
|
+
subject.authorize
|
|
102
|
+
subject.access_token.should_not eq(expired_access_token)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe "finding the current access token" do
|
|
107
|
+
subject { PasswordAccessTokenRequest.new(client, owner, params) }
|
|
108
|
+
it { should be_valid }
|
|
109
|
+
its(:error) { should be_nil }
|
|
110
|
+
|
|
111
|
+
before { subject.authorize }
|
|
112
|
+
|
|
113
|
+
it "should find the access token and not create a new one" do
|
|
114
|
+
subject.should_not_receive(:create_access_token)
|
|
115
|
+
access_token = subject.authorize
|
|
116
|
+
subject.access_token.should eq(access_token)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe "creating the first access_token" do
|
|
121
|
+
subject { PasswordAccessTokenRequest.new(client, owner, params) }
|
|
122
|
+
it { should be_valid }
|
|
123
|
+
its(:error) { should be_nil }
|
|
124
|
+
|
|
125
|
+
it "should create a new access token" do
|
|
126
|
+
subject.should_receive(:create_access_token)
|
|
127
|
+
subject.authorize
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe "with errors" do
|
|
132
|
+
def token(params)
|
|
133
|
+
PasswordAccessTokenRequest.new(client, owner, params)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "includes the error in the response" do
|
|
137
|
+
access_token = token(params.except(:grant_type))
|
|
138
|
+
access_token.error_response.name.should == :invalid_request
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe "when client is not present" do
|
|
142
|
+
subject { PasswordAccessTokenRequest.new(nil, owner, params) }
|
|
143
|
+
its(:error) { should == :invalid_client }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
describe "when :grant_type is not 'password'" do
|
|
147
|
+
subject { token(params.merge(:grant_type => "invalid")) }
|
|
148
|
+
its(:error) { should == :unsupported_grant_type }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'active_support/core_ext/module/delegation'
|
|
3
|
+
require 'active_support/core_ext/string'
|
|
4
|
+
require 'doorkeeper/oauth/scopes'
|
|
5
|
+
|
|
6
|
+
module Doorkeeper::OAuth
|
|
7
|
+
describe Scopes do
|
|
8
|
+
describe :add do
|
|
9
|
+
it 'allows you to add scopes with symbols' do
|
|
10
|
+
subject.add :public
|
|
11
|
+
subject.all.should == [:public]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'allows you to add scopes with strings' do
|
|
15
|
+
subject.add "public"
|
|
16
|
+
subject.all.should == [:public]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'do not add already included scopes' do
|
|
20
|
+
subject.add :public
|
|
21
|
+
subject.add :public
|
|
22
|
+
subject.all.should == [:public]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe :exists do
|
|
27
|
+
before do
|
|
28
|
+
subject.add :public
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'returns true if scope with given name is present' do
|
|
32
|
+
subject.exists?("public").should be_true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'returns false if scope with given name does not exist' do
|
|
36
|
+
subject.exists?("other").should be_false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'handles symbols' do
|
|
40
|
+
subject.exists?(:public).should be_true
|
|
41
|
+
subject.exists?(:other).should be_false
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe ".from_string" do
|
|
46
|
+
let(:string) { "public write" }
|
|
47
|
+
|
|
48
|
+
subject { Scopes.from_string(string) }
|
|
49
|
+
|
|
50
|
+
it { should be_a(Scopes) }
|
|
51
|
+
its(:all) { should == [:public, :write] }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe :+ do
|
|
55
|
+
it "can add to another scope object" do
|
|
56
|
+
scopes = Scopes.from_string("public") + Scopes.from_string("admin")
|
|
57
|
+
scopes.all.should == [:public, :admin]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "does not change the existing object" do
|
|
61
|
+
origin = Scopes.from_string("public")
|
|
62
|
+
new_scope = origin + Scopes.from_string("admin")
|
|
63
|
+
origin.to_s.should == "public"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "raises an error if cannot handle addition" do
|
|
67
|
+
expect {
|
|
68
|
+
Scopes.from_string("public") + "admin"
|
|
69
|
+
}.to raise_error(NoMethodError)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe :== do
|
|
74
|
+
it 'is equal to another set of scopes' do
|
|
75
|
+
Scopes.from_string("public").should == Scopes.from_string("public")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'is equal to another set of scopes with no particular order' do
|
|
79
|
+
Scopes.from_string("public write").should == Scopes.from_string("write public")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'differs from another set of scopes when scopes are not the same' do
|
|
83
|
+
Scopes.from_string("public write").should_not == Scopes.from_string("write")
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe :has_scopes? do
|
|
88
|
+
subject { Scopes.from_string("public admin") }
|
|
89
|
+
|
|
90
|
+
it "returns true when at least one scope is included" do
|
|
91
|
+
subject.has_scopes?(Scopes.from_string("public")).should be_true
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "returns true when all scopes are included" do
|
|
95
|
+
subject.has_scopes?(Scopes.from_string("public admin")).should be_true
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "is true if all scopes are included in any order" do
|
|
99
|
+
subject.has_scopes?(Scopes.from_string("admin public")).should be_true
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "is false if no scopes are included" do
|
|
103
|
+
subject.has_scopes?(Scopes.from_string("notexistent")).should be_false
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "returns false when any scope is not included" do
|
|
107
|
+
subject.has_scopes?(Scopes.from_string("public nope")).should be_false
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "is false if no scopes are included even for existing ones" do
|
|
111
|
+
subject.has_scopes?(Scopes.from_string("public admin notexistent")).should be_false
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'spec_helper_integration'
|
|
2
|
+
|
|
3
|
+
describe Doorkeeper::AccessGrant do
|
|
4
|
+
subject { FactoryGirl.build(:access_grant) }
|
|
5
|
+
|
|
6
|
+
it { should be_valid }
|
|
7
|
+
|
|
8
|
+
it_behaves_like "an accessible token"
|
|
9
|
+
it_behaves_like "a revocable token"
|
|
10
|
+
it_behaves_like "an unique token" do
|
|
11
|
+
let(:factory_name) { :access_grant }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "validations" do
|
|
15
|
+
it "is invalid without resource_owner_id" do
|
|
16
|
+
subject.resource_owner_id = nil
|
|
17
|
+
should_not be_valid
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "is invalid without application_id" do
|
|
21
|
+
subject.application_id = nil
|
|
22
|
+
should_not be_valid
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "is invalid without token" do
|
|
26
|
+
subject.save
|
|
27
|
+
subject.token = nil
|
|
28
|
+
should_not be_valid
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "is invalid without expires_in" do
|
|
32
|
+
subject.expires_in = nil
|
|
33
|
+
should_not be_valid
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require 'spec_helper_integration'
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
describe AccessToken do
|
|
5
|
+
subject { FactoryGirl.build(:access_token) }
|
|
6
|
+
|
|
7
|
+
it { should be_valid }
|
|
8
|
+
|
|
9
|
+
it_behaves_like "an accessible token"
|
|
10
|
+
it_behaves_like "a revocable token"
|
|
11
|
+
it_behaves_like "an unique token" do
|
|
12
|
+
let(:factory_name) { :access_token }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "validations" do
|
|
16
|
+
it "is valid without resource_owner_id" do
|
|
17
|
+
# For client credentials flow
|
|
18
|
+
subject.resource_owner_id = nil
|
|
19
|
+
should be_valid
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "is invalid without application_id" do
|
|
23
|
+
subject.application_id = nil
|
|
24
|
+
should_not be_valid
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe '.revoke_all_for' do
|
|
29
|
+
let(:resource_owner) { stub(:id => 100) }
|
|
30
|
+
let(:application) { FactoryGirl.create :application }
|
|
31
|
+
let(:default_attributes) do
|
|
32
|
+
{ :application => application, :resource_owner_id => resource_owner.id }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'revokes all tokens for given application and resource owner' do
|
|
36
|
+
FactoryGirl.create :access_token, default_attributes
|
|
37
|
+
AccessToken.revoke_all_for application.id, resource_owner
|
|
38
|
+
AccessToken.all.should be_empty
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'matches application' do
|
|
42
|
+
FactoryGirl.create :access_token, default_attributes.merge(:application => FactoryGirl.create(:application))
|
|
43
|
+
AccessToken.revoke_all_for application.id, resource_owner
|
|
44
|
+
AccessToken.all.should_not be_empty
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'matches resource owner' do
|
|
48
|
+
FactoryGirl.create :access_token, default_attributes.merge(:resource_owner_id => 90)
|
|
49
|
+
AccessToken.revoke_all_for application.id, resource_owner
|
|
50
|
+
AccessToken.all.should_not be_empty
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe '.matching_token_for' do
|
|
55
|
+
let(:resource_owner_id) { 100 }
|
|
56
|
+
let(:application) { FactoryGirl.create :application }
|
|
57
|
+
let(:scopes) { Doorkeeper::OAuth::Scopes.from_string("public write") }
|
|
58
|
+
let(:default_attributes) do
|
|
59
|
+
{ :application => application, :resource_owner_id => resource_owner_id, :scopes => scopes.to_s }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'returns only one token' do
|
|
63
|
+
token = FactoryGirl.create :access_token, default_attributes
|
|
64
|
+
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
|
65
|
+
last_token.should == token
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'accepts resource owner as object' do
|
|
69
|
+
resource_owner = stub(:kind_of? => true, :id => 100)
|
|
70
|
+
token = FactoryGirl.create :access_token, default_attributes
|
|
71
|
+
last_token = AccessToken.matching_token_for(application, resource_owner, scopes)
|
|
72
|
+
last_token.should == token
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'accepts nil as resource owner' do
|
|
76
|
+
token = FactoryGirl.create :access_token, default_attributes.merge(:resource_owner_id => nil)
|
|
77
|
+
last_token = AccessToken.matching_token_for(application, nil, scopes)
|
|
78
|
+
last_token.should == token
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'excludes revoked tokens' do
|
|
82
|
+
FactoryGirl.create :access_token, default_attributes.merge(:revoked_at => 1.day.ago)
|
|
83
|
+
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
|
84
|
+
last_token.should be_nil
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'matches the application' do
|
|
88
|
+
token = FactoryGirl.create :access_token, default_attributes.merge(:application => FactoryGirl.create(:application))
|
|
89
|
+
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
|
90
|
+
last_token.should be_nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'matches the resource owner' do
|
|
94
|
+
FactoryGirl.create :access_token, default_attributes.merge(:resource_owner_id => 2)
|
|
95
|
+
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
|
96
|
+
last_token.should be_nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'matches the scopes' do
|
|
100
|
+
FactoryGirl.create :access_token, default_attributes.merge(:scopes => 'public email')
|
|
101
|
+
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
|
102
|
+
last_token.should be_nil
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'returns the last created token' do
|
|
106
|
+
FactoryGirl.create :access_token, default_attributes.merge(:created_at => 1.day.ago)
|
|
107
|
+
token = FactoryGirl.create :access_token, default_attributes
|
|
108
|
+
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
|
109
|
+
last_token.should == token
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
require 'spec_helper_integration'
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
describe Application do
|
|
5
|
+
let(:new_application) { FactoryGirl.build(:application) }
|
|
6
|
+
|
|
7
|
+
it 'is valid given valid attributes' do
|
|
8
|
+
new_application.should be_valid
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'is invalid without a name' do
|
|
12
|
+
new_application.name = nil
|
|
13
|
+
new_application.should_not be_valid
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'generates uid on create' do
|
|
17
|
+
new_application.uid.should be_nil
|
|
18
|
+
new_application.save
|
|
19
|
+
new_application.uid.should_not be_nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'is invalid without uid' do
|
|
23
|
+
new_application.save
|
|
24
|
+
new_application.uid = nil
|
|
25
|
+
new_application.should_not be_valid
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'is invalid without redirect_uri' do
|
|
29
|
+
new_application.save
|
|
30
|
+
new_application.redirect_uri = nil
|
|
31
|
+
new_application.should_not be_valid
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'is invalid with a redirect_uri that is relative' do
|
|
35
|
+
new_application.save
|
|
36
|
+
new_application.redirect_uri = "/abcd"
|
|
37
|
+
new_application.should_not be_valid
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'is invalid with a redirect_uri that has a fragment' do
|
|
41
|
+
new_application.save
|
|
42
|
+
new_application.redirect_uri = "http://example.com/abcd#xyz"
|
|
43
|
+
new_application.should_not be_valid
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'is invalid with a redirect_uri that has a query parameter' do
|
|
47
|
+
new_application.save
|
|
48
|
+
new_application.redirect_uri = "http://example.com/abcd?xyz=123"
|
|
49
|
+
new_application.should_not be_valid
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'checks uniqueness of uid' do
|
|
53
|
+
app1 = FactoryGirl.create(:application)
|
|
54
|
+
app2 = FactoryGirl.create(:application)
|
|
55
|
+
app2.uid = app1.uid
|
|
56
|
+
app2.should_not be_valid
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'generate secret on create' do
|
|
60
|
+
new_application.secret.should be_nil
|
|
61
|
+
new_application.save
|
|
62
|
+
new_application.secret.should_not be_nil
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'is invalid without secret' do
|
|
66
|
+
new_application.save
|
|
67
|
+
new_application.secret = nil
|
|
68
|
+
new_application.should_not be_valid
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe 'destroy related models on cascade' do
|
|
72
|
+
before(:each) do
|
|
73
|
+
new_application.save
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'should destroy its access grants' do
|
|
77
|
+
FactoryGirl.create(:access_grant, :application => new_application)
|
|
78
|
+
expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'should destroy its access tokens' do
|
|
82
|
+
FactoryGirl.create(:access_token, :application => new_application)
|
|
83
|
+
FactoryGirl.create(:access_token, :application => new_application, :revoked_at => Time.now)
|
|
84
|
+
expect { new_application.destroy }.to change { Doorkeeper::AccessToken.count }.by(-2)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe :authorized_for do
|
|
89
|
+
let(:resource_owner) { double(:resource_owner, :id => 10) }
|
|
90
|
+
|
|
91
|
+
it "is empty if the application is not authorized for anyone" do
|
|
92
|
+
Application.authorized_for(resource_owner).should be_empty
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "returns only application for a specific resource owner" do
|
|
96
|
+
FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id + 1)
|
|
97
|
+
token = FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id)
|
|
98
|
+
Application.authorized_for(resource_owner).should == [token.application]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "excludes revoked tokens" do
|
|
102
|
+
FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id, :revoked_at => 2.days.ago)
|
|
103
|
+
Application.authorized_for(resource_owner).should be_empty
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "returns all applications that have been authorized" do
|
|
107
|
+
token1 = FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id)
|
|
108
|
+
token2 = FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id)
|
|
109
|
+
Application.authorized_for(resource_owner).should == [token1.application, token2.application]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "returns only one application even if it has been authorized twice" do
|
|
113
|
+
application = FactoryGirl.create(:application)
|
|
114
|
+
FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id, :application => application)
|
|
115
|
+
FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id, :application => application)
|
|
116
|
+
Application.authorized_for(resource_owner).should == [application]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "should fail to mass assign a new application" do
|
|
120
|
+
mass_assign = { :name => 'Something',
|
|
121
|
+
:redirect_uri => 'http://somewhere.com/something',
|
|
122
|
+
:uid => 123,
|
|
123
|
+
:secret => 'something' }
|
|
124
|
+
Application.create(mass_assign).uid.should_not == 123
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require 'spec_helper_integration'
|
|
2
|
+
|
|
3
|
+
feature 'Adding applications' do
|
|
4
|
+
context 'in application form' do
|
|
5
|
+
background do
|
|
6
|
+
visit '/oauth/applications/new'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
scenario 'adding a valid app' do
|
|
10
|
+
fill_in 'Name', :with => 'My Application'
|
|
11
|
+
fill_in 'Redirect uri', :with => 'http://example.com'
|
|
12
|
+
click_button 'Submit'
|
|
13
|
+
i_should_see 'Application created'
|
|
14
|
+
i_should_see 'My Application'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
scenario 'adding invalid app' do
|
|
18
|
+
click_button 'Submit'
|
|
19
|
+
i_should_see 'Whoops! Check your form for possible errors'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
feature 'Listing applications' do
|
|
25
|
+
background do
|
|
26
|
+
FactoryGirl.create :application, :name => 'Oauth Dude'
|
|
27
|
+
FactoryGirl.create :application, :name => 'Awesome App'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
scenario 'application list' do
|
|
31
|
+
visit '/oauth/applications'
|
|
32
|
+
i_should_see 'Awesome App'
|
|
33
|
+
i_should_see 'Oauth Dude'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
feature 'Show application' do
|
|
38
|
+
let :app do
|
|
39
|
+
FactoryGirl.create :application, :name => 'Just another oauth app'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
scenario 'visiting application page' do
|
|
43
|
+
visit "/oauth/applications/#{app.id}"
|
|
44
|
+
i_should_see 'Just another oauth app'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
feature 'Edit application' do
|
|
49
|
+
let :app do
|
|
50
|
+
FactoryGirl.create :application, :name => 'OMG my app'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
background do
|
|
54
|
+
visit "/oauth/applications/#{app.id}/edit"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
scenario 'updating a valid app' do
|
|
58
|
+
fill_in :name, :with => "Serious app"
|
|
59
|
+
click_button 'Submit'
|
|
60
|
+
i_should_see "Application updated"
|
|
61
|
+
i_should_see "Serious app"
|
|
62
|
+
i_should_not_see "OMG my app"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
scenario 'updating an invalid app' do
|
|
66
|
+
fill_in :name, :with => ""
|
|
67
|
+
click_button 'Submit'
|
|
68
|
+
i_should_see 'Whoops! Check your form for possible errors'
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
feature 'Destroy application' do
|
|
73
|
+
background do
|
|
74
|
+
@app = FactoryGirl.create :application
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
scenario 'deleting an application from list' do
|
|
78
|
+
visit "/oauth/applications"
|
|
79
|
+
i_should_see @app.name
|
|
80
|
+
within(:css, "tr#application_#{@app.id}") do
|
|
81
|
+
click_link "Destroy"
|
|
82
|
+
end
|
|
83
|
+
i_should_see "Application deleted"
|
|
84
|
+
i_should_not_see @app.name
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
scenario 'deleting an application from show' do
|
|
88
|
+
visit "/oauth/applications/#{@app.id}"
|
|
89
|
+
click_link 'Remove'
|
|
90
|
+
i_should_see "Application deleted"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'spec_helper_integration'
|
|
2
|
+
|
|
3
|
+
feature 'Authorized applications' do
|
|
4
|
+
background do
|
|
5
|
+
@user = User.create!(:name => "Joe", :password => "sekret")
|
|
6
|
+
@client = client_exists(:name => "Amazing Client App")
|
|
7
|
+
resource_owner_is_authenticated @user
|
|
8
|
+
client_is_authorized @client, @user
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
scenario "display user's authorized applications" do
|
|
12
|
+
visit '/oauth/authorized_applications'
|
|
13
|
+
i_should_see 'Amazing Client App'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
scenario "do not display other user's authorized applications" do
|
|
17
|
+
client = client_exists(:name => "Another Client App")
|
|
18
|
+
client_is_authorized client, User.create!(:name => "Joe", :password => "sekret")
|
|
19
|
+
visit '/oauth/authorized_applications'
|
|
20
|
+
i_should_not_see 'Another Client App'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
scenario "user revoke access to application" do
|
|
24
|
+
visit '/oauth/authorized_applications'
|
|
25
|
+
i_should_see 'Amazing Client App'
|
|
26
|
+
click_on 'Revoke'
|
|
27
|
+
i_should_see 'Application revoked'
|
|
28
|
+
i_should_not_see 'Amazing Client App'
|
|
29
|
+
end
|
|
30
|
+
end
|