doorkeeper 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (92) hide show
  1. data/CHANGELOG.md +13 -0
  2. data/README.md +32 -5
  3. data/app/controllers/doorkeeper/application_controller.rb +4 -11
  4. data/app/controllers/doorkeeper/authorizations_controller.rb +11 -2
  5. data/app/controllers/doorkeeper/tokens_controller.rb +19 -5
  6. data/app/models/doorkeeper/access_grant.rb +1 -8
  7. data/app/models/doorkeeper/access_token.rb +2 -10
  8. data/app/models/doorkeeper/application.rb +4 -0
  9. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  10. data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
  11. data/config/locales/en.yml +3 -0
  12. data/doorkeeper.gemspec +2 -1
  13. data/lib/doorkeeper.rb +23 -3
  14. data/lib/doorkeeper/config.rb +73 -12
  15. data/lib/doorkeeper/doorkeeper_for.rb +1 -1
  16. data/lib/doorkeeper/engine.rb +28 -0
  17. data/lib/doorkeeper/models/scopes.rb +13 -0
  18. data/lib/doorkeeper/oauth/access_token_request.rb +5 -16
  19. data/lib/doorkeeper/oauth/authorization/code.rb +1 -1
  20. data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
  21. data/lib/doorkeeper/oauth/authorization_request.rb +18 -23
  22. data/lib/doorkeeper/oauth/client.rb +27 -0
  23. data/lib/doorkeeper/oauth/client/credentials.rb +21 -0
  24. data/lib/doorkeeper/oauth/client/methods.rb +18 -0
  25. data/lib/doorkeeper/oauth/client_credentials/creator.rb +29 -0
  26. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +35 -0
  27. data/lib/doorkeeper/oauth/client_credentials/response.rb +42 -0
  28. data/lib/doorkeeper/oauth/client_credentials/validation.rb +33 -0
  29. data/lib/doorkeeper/oauth/client_credentials_request.rb +46 -0
  30. data/lib/doorkeeper/oauth/error.rb +9 -0
  31. data/lib/doorkeeper/oauth/error_response.rb +30 -0
  32. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -2
  33. data/lib/doorkeeper/oauth/password_access_token_request.rb +130 -0
  34. data/lib/doorkeeper/oauth/scopes.rb +60 -0
  35. data/lib/doorkeeper/version.rb +1 -1
  36. data/lib/generators/doorkeeper/templates/initializer.rb +10 -5
  37. data/lib/generators/doorkeeper/templates/migration.rb +1 -1
  38. data/script/run_all +11 -0
  39. data/spec/controllers/authorizations_controller_spec.rb +3 -3
  40. data/spec/controllers/protected_resources_controller_spec.rb +7 -0
  41. data/spec/controllers/tokens_controller_spec.rb +1 -1
  42. data/spec/dummy/app/controllers/home_controller.rb +1 -1
  43. data/spec/dummy/app/models/user.rb +9 -0
  44. data/spec/dummy/config/application.rb +2 -0
  45. data/spec/dummy/config/initializers/doorkeeper.rb +12 -5
  46. data/spec/dummy/config/locales/doorkeeper.en.yml +5 -0
  47. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +5 -0
  48. data/spec/dummy/db/migrate/{20111206151426_create_doorkeeper_tables.rb → 20120524202412_create_doorkeeper_tables.rb} +10 -1
  49. data/spec/dummy/db/schema.rb +15 -6
  50. data/spec/lib/config_spec.rb +29 -13
  51. data/spec/lib/models/scopes_spec.rb +32 -0
  52. data/spec/lib/oauth/access_token_request_spec.rb +15 -29
  53. data/spec/lib/oauth/authorization_request_spec.rb +22 -72
  54. data/spec/lib/oauth/client/credentials_spec.rb +47 -0
  55. data/spec/lib/oauth/client/methods_spec.rb +54 -0
  56. data/spec/lib/oauth/client_credentials/creator_spec.rb +47 -0
  57. data/spec/lib/oauth/client_credentials/issuer_spec.rb +57 -0
  58. data/spec/lib/oauth/client_credentials/response_spec.rb +58 -0
  59. data/spec/lib/oauth/client_credentials/validation_spec.rb +29 -0
  60. data/spec/lib/oauth/client_credentials_integration_spec.rb +27 -0
  61. data/spec/lib/oauth/client_credentials_request_spec.rb +60 -0
  62. data/spec/lib/oauth/client_spec.rb +42 -0
  63. data/spec/lib/oauth/error_response_spec.rb +40 -0
  64. data/spec/lib/oauth/error_spec.rb +19 -0
  65. data/spec/lib/oauth/helpers/scope_checker_spec.rb +15 -10
  66. data/spec/lib/oauth/password_access_token_request_spec.rb +152 -0
  67. data/spec/lib/oauth/scopes_spec.rb +115 -0
  68. data/spec/models/doorkeeper/access_grant_spec.rb +0 -15
  69. data/spec/models/doorkeeper/access_token_spec.rb +11 -4
  70. data/spec/requests/applications/authorized_applications_spec.rb +2 -2
  71. data/spec/requests/endpoints/authorization_spec.rb +2 -2
  72. data/spec/requests/endpoints/token_spec.rb +7 -0
  73. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  74. data/spec/requests/flows/authorization_code_spec.rb +8 -2
  75. data/spec/requests/flows/client_credentials_spec.rb +56 -0
  76. data/spec/requests/flows/password_spec.rb +52 -0
  77. data/spec/requests/flows/skip_authorization_spec.rb +2 -2
  78. data/spec/requests/protected_resources/private_api_spec.rb +9 -2
  79. data/spec/spec_helper_integration.rb +3 -0
  80. data/spec/support/helpers/authorization_request_helper.rb +7 -5
  81. data/spec/support/helpers/model_helper.rb +3 -3
  82. data/spec/support/helpers/request_spec_helper.rb +1 -1
  83. data/spec/support/helpers/url_helper.rb +12 -0
  84. metadata +65 -30
  85. data/lib/doorkeeper/config/scope.rb +0 -11
  86. data/lib/doorkeeper/config/scopes.rb +0 -61
  87. data/lib/doorkeeper/config/scopes_builder.rb +0 -18
  88. data/spec/dummy/config/initializers/inflections.rb +0 -10
  89. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  90. data/spec/lib/config/scope_spec.rb +0 -45
  91. data/spec/lib/config/scopes_builder_spec.rb +0 -27
  92. data/spec/lib/config/scopes_spec.rb +0 -180
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ require 'active_support/i18n'
3
+ require 'doorkeeper/oauth/error'
4
+
5
+ module Doorkeeper::OAuth
6
+ describe Error do
7
+ subject { Error.new(:some_error, :some_state) }
8
+
9
+ it { should respond_to(:name) }
10
+ it { should respond_to(:state) }
11
+
12
+ describe :description do
13
+ it 'is translated from translation messages' do
14
+ I18n.should_receive(:translate).with(:some_error, :scope => [:doorkeeper, :errors, :messages])
15
+ subject.description
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,30 +1,35 @@
1
1
  require 'spec_helper'
2
2
  require 'active_support/core_ext/string'
3
3
  require 'doorkeeper/oauth/helpers/scope_checker'
4
+ require 'doorkeeper/oauth/scopes'
4
5
 
5
6
  module Doorkeeper::OAuth::Helpers
6
7
  describe ScopeChecker, ".matches?" do
8
+ def new_scope(*args)
9
+ Doorkeeper::OAuth::Scopes.from_array args
10
+ end
11
+
7
12
  it "true if scopes matches" do
8
- scopes = [:public]
9
- scopes_to_match = "public"
13
+ scopes = new_scope :public
14
+ scopes_to_match = new_scope :public
10
15
  ScopeChecker.matches?(scopes, scopes_to_match).should be_true
11
16
  end
12
17
 
13
18
  it "is false when scopes differs" do
14
- scopes = [:public]
15
- scopes_to_match = "write"
19
+ scopes = new_scope :public
20
+ scopes_to_match = new_scope :write
16
21
  ScopeChecker.matches?(scopes, scopes_to_match).should be_false
17
22
  end
18
23
 
19
24
  it "is false when scope in array is missing" do
20
- scopes = [:public]
21
- scopes_to_match = "public write"
25
+ scopes = new_scope :public
26
+ scopes_to_match = new_scope :public, :write
22
27
  ScopeChecker.matches?(scopes, scopes_to_match).should be_false
23
28
  end
24
29
 
25
30
  it "is false when scope in string is missing" do
26
- scopes = [:public, :write]
27
- scopes_to_match = "public"
31
+ scopes = new_scope :public, :write
32
+ scopes_to_match = new_scope :public
28
33
  ScopeChecker.matches?(scopes, scopes_to_match).should be_false
29
34
  end
30
35
 
@@ -35,9 +40,10 @@ module Doorkeeper::OAuth::Helpers
35
40
  end
36
41
 
37
42
  describe ScopeChecker, ".valid?" do
38
- let(:server_scopes) { double :all_included? => true }
43
+ let(:server_scopes) { Doorkeeper::OAuth::Scopes.new }
39
44
 
40
45
  it "is valid if scope is present" do
46
+ server_scopes.add :scope
41
47
  ScopeChecker.valid?("scope", server_scopes).should be_true
42
48
  end
43
49
 
@@ -62,7 +68,6 @@ module Doorkeeper::OAuth::Helpers
62
68
  end
63
69
 
64
70
  it "is invalid if any scope is not included in server scopes" do
65
- server_scopes.stub(:all_included?).and_return(false)
66
71
  ScopeChecker.valid?("scope another", server_scopes).should be_false
67
72
  end
68
73
  end
@@ -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
@@ -33,19 +33,4 @@ describe Doorkeeper::AccessGrant do
33
33
  should_not be_valid
34
34
  end
35
35
  end
36
-
37
- describe :scopes do
38
- it "is nil when scopes are not set" do
39
- subject.scopes = nil
40
- subject.scopes.should be_nil
41
- end
42
-
43
- describe "returns an array of scopes" do
44
- subject { FactoryGirl.create(:access_grant, :scopes => "public write").scopes }
45
-
46
- it { should be_kind_of(Array) }
47
- its(:count) { should == 2 }
48
- it { should include(:public, :write) }
49
- end
50
- end
51
36
  end
@@ -13,9 +13,10 @@ module Doorkeeper
13
13
  end
14
14
 
15
15
  describe "validations" do
16
- it "is invalid without resource_owner_id" do
16
+ it "is valid without resource_owner_id" do
17
+ # For client credentials flow
17
18
  subject.resource_owner_id = nil
18
- should_not be_valid
19
+ should be_valid
19
20
  end
20
21
 
21
22
  it "is invalid without application_id" do
@@ -53,9 +54,9 @@ module Doorkeeper
53
54
  describe '.matching_token_for' do
54
55
  let(:resource_owner_id) { 100 }
55
56
  let(:application) { FactoryGirl.create :application }
56
- let(:scopes) { "public write" }
57
+ let(:scopes) { Doorkeeper::OAuth::Scopes.from_string("public write") }
57
58
  let(:default_attributes) do
58
- { :application => application, :resource_owner_id => resource_owner_id, :scopes => scopes }
59
+ { :application => application, :resource_owner_id => resource_owner_id, :scopes => scopes.to_s }
59
60
  end
60
61
 
61
62
  it 'returns only one token' do
@@ -71,6 +72,12 @@ module Doorkeeper
71
72
  last_token.should == token
72
73
  end
73
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
+
74
81
  it 'excludes revoked tokens' do
75
82
  FactoryGirl.create :access_token, default_attributes.merge(:revoked_at => 1.day.ago)
76
83
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
@@ -2,7 +2,7 @@ require 'spec_helper_integration'
2
2
 
3
3
  feature 'Authorized applications' do
4
4
  background do
5
- @user = User.create!
5
+ @user = User.create!(:name => "Joe", :password => "sekret")
6
6
  @client = client_exists(:name => "Amazing Client App")
7
7
  resource_owner_is_authenticated @user
8
8
  client_is_authorized @client, @user
@@ -15,7 +15,7 @@ feature 'Authorized applications' do
15
15
 
16
16
  scenario "do not display other user's authorized applications" do
17
17
  client = client_exists(:name => "Another Client App")
18
- client_is_authorized client, User.create!
18
+ client_is_authorized client, User.create!(:name => "Joe", :password => "sekret")
19
19
  visit '/oauth/authorized_applications'
20
20
  i_should_not_see 'Another Client App'
21
21
  end
@@ -38,8 +38,8 @@ feature 'Authorization endpoint' do
38
38
  background do
39
39
  create_resource_owner
40
40
  sign_in
41
- scope_exists :public, :default => true, :description => "Access your public data"
42
- scope_exists :write, :description => "Update your data"
41
+ default_scopes_exist :public
42
+ optional_scopes_exist :write
43
43
  end
44
44
 
45
45
  scenario "displays default scopes when no scope was requested" do
@@ -19,4 +19,11 @@ feature 'Token endpoint' do
19
19
 
20
20
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
21
21
  end
22
+
23
+ scenario 'returns null for expires_in when a permanent token is set' do
24
+ config_is_set(:access_token_expires_in, nil)
25
+ post token_endpoint_url(:code => @authorization.token, :client => @client)
26
+ should_have_json 'access_token', Doorkeeper::AccessToken.first.token
27
+ should_have_json 'expires_in', nil
28
+ end
22
29
  end