doorkeeper 3.1.0 → 4.4.3

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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.github/ISSUE_TEMPLATE.md +25 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  5. data/.gitignore +6 -1
  6. data/.hound.yml +2 -13
  7. data/.rubocop.yml +17 -0
  8. data/.travis.yml +26 -10
  9. data/Appraisals +18 -0
  10. data/CODE_OF_CONDUCT.md +46 -0
  11. data/CONTRIBUTING.md +2 -0
  12. data/Gemfile +5 -5
  13. data/NEWS.md +141 -2
  14. data/README.md +149 -66
  15. data/RELEASING.md +5 -12
  16. data/Rakefile +1 -1
  17. data/SECURITY.md +15 -0
  18. data/app/controllers/doorkeeper/application_controller.rb +4 -6
  19. data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
  20. data/app/controllers/doorkeeper/applications_controller.rb +18 -8
  21. data/app/controllers/doorkeeper/authorizations_controller.rb +1 -1
  22. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  23. data/app/controllers/doorkeeper/tokens_controller.rb +62 -15
  24. data/app/helpers/doorkeeper/dashboard_helper.rb +14 -10
  25. data/app/validators/redirect_uri_validator.rb +12 -2
  26. data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
  27. data/app/views/doorkeeper/applications/_form.html.erb +13 -2
  28. data/app/views/doorkeeper/applications/index.html.erb +2 -0
  29. data/app/views/doorkeeper/applications/show.html.erb +4 -1
  30. data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
  31. data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
  32. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  33. data/app/views/layouts/doorkeeper/admin.html.erb +1 -1
  34. data/config/locales/en.yml +12 -7
  35. data/doorkeeper.gemspec +16 -11
  36. data/gemfiles/rails_4_2.gemfile +13 -0
  37. data/gemfiles/rails_5_0.gemfile +12 -0
  38. data/gemfiles/rails_5_1.gemfile +12 -0
  39. data/gemfiles/rails_5_2.gemfile +12 -0
  40. data/gemfiles/rails_master.gemfile +14 -0
  41. data/lib/doorkeeper/config.rb +119 -46
  42. data/lib/doorkeeper/engine.rb +11 -7
  43. data/lib/doorkeeper/errors.rb +18 -0
  44. data/lib/doorkeeper/grape/helpers.rb +14 -8
  45. data/lib/doorkeeper/helpers/controller.rb +8 -19
  46. data/lib/doorkeeper/models/access_grant_mixin.rb +10 -21
  47. data/lib/doorkeeper/models/access_token_mixin.rb +147 -43
  48. data/lib/doorkeeper/models/application_mixin.rb +33 -35
  49. data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
  50. data/lib/doorkeeper/models/concerns/expirable.rb +15 -5
  51. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  52. data/lib/doorkeeper/models/concerns/ownership.rb +6 -1
  53. data/lib/doorkeeper/models/concerns/revocable.rb +37 -2
  54. data/lib/doorkeeper/oauth/authorization/token.rb +22 -18
  55. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
  56. data/lib/doorkeeper/oauth/authorization_code_request.rb +7 -5
  57. data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +9 -2
  58. data/lib/doorkeeper/oauth/base_response.rb +29 -0
  59. data/lib/doorkeeper/oauth/client/credentials.rb +21 -8
  60. data/lib/doorkeeper/oauth/client.rb +2 -3
  61. data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
  62. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
  63. data/lib/doorkeeper/oauth/client_credentials/validation.rb +1 -1
  64. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -8
  65. data/lib/doorkeeper/oauth/code_response.rb +16 -16
  66. data/lib/doorkeeper/oauth/error.rb +2 -2
  67. data/lib/doorkeeper/oauth/error_response.rb +10 -10
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +17 -1
  71. data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -4
  72. data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -13
  73. data/lib/doorkeeper/oauth/pre_authorization.rb +5 -3
  74. data/lib/doorkeeper/oauth/refresh_token_request.rb +23 -14
  75. data/lib/doorkeeper/oauth/scopes.rb +18 -8
  76. data/lib/doorkeeper/oauth/token.rb +20 -21
  77. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  78. data/lib/doorkeeper/oauth/token_request.rb +1 -2
  79. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +34 -8
  82. data/lib/doorkeeper/orm/active_record/application.rb +48 -11
  83. data/lib/doorkeeper/orm/active_record.rb +17 -22
  84. data/lib/doorkeeper/rails/helpers.rb +6 -9
  85. data/lib/doorkeeper/rails/routes/mapper.rb +4 -4
  86. data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
  87. data/lib/doorkeeper/rails/routes.rb +17 -11
  88. data/lib/doorkeeper/request/authorization_code.rb +7 -1
  89. data/lib/doorkeeper/request/password.rb +2 -2
  90. data/lib/doorkeeper/request/refresh_token.rb +1 -1
  91. data/lib/doorkeeper/request.rb +7 -1
  92. data/lib/doorkeeper/server.rb +0 -8
  93. data/lib/doorkeeper/validations.rb +3 -2
  94. data/lib/doorkeeper/version.rb +34 -1
  95. data/lib/doorkeeper.rb +10 -2
  96. data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +31 -0
  97. data/lib/generators/doorkeeper/application_owner_generator.rb +11 -2
  98. data/lib/generators/doorkeeper/migration_generator.rb +13 -1
  99. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +35 -0
  100. data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +11 -0
  101. data/{spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb → lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb} +1 -1
  102. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +11 -0
  103. data/lib/generators/doorkeeper/templates/initializer.rb +38 -6
  104. data/lib/generators/doorkeeper/templates/migration.rb.erb +69 -0
  105. data/spec/controllers/application_metal_controller.rb +10 -0
  106. data/spec/controllers/applications_controller_spec.rb +15 -4
  107. data/spec/controllers/authorizations_controller_spec.rb +74 -27
  108. data/spec/controllers/protected_resources_controller_spec.rb +70 -32
  109. data/spec/controllers/token_info_controller_spec.rb +17 -13
  110. data/spec/controllers/tokens_controller_spec.rb +198 -12
  111. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -4
  112. data/spec/dummy/app/controllers/home_controller.rb +1 -1
  113. data/spec/dummy/app/controllers/metal_controller.rb +1 -1
  114. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +3 -3
  115. data/spec/dummy/app/models/user.rb +0 -4
  116. data/spec/dummy/config/application.rb +2 -36
  117. data/spec/dummy/config/environment.rb +1 -1
  118. data/spec/dummy/config/environments/test.rb +4 -15
  119. data/spec/dummy/config/initializers/doorkeeper.rb +19 -3
  120. data/spec/dummy/config/initializers/new_framework_defaults.rb +6 -0
  121. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  122. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  123. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  124. data/{lib/generators/doorkeeper/templates/migration.rb → spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb} +16 -4
  125. data/{lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb → spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb} +4 -2
  126. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +13 -0
  127. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb +13 -0
  128. data/spec/dummy/db/schema.rb +24 -22
  129. data/spec/factories.rb +4 -2
  130. data/spec/generators/application_owner_generator_spec.rb +24 -5
  131. data/spec/generators/migration_generator_spec.rb +24 -3
  132. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  133. data/spec/grape/grape_integration_spec.rb +135 -0
  134. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  135. data/spec/lib/config_spec.rb +159 -14
  136. data/spec/lib/doorkeeper_spec.rb +135 -13
  137. data/spec/lib/models/expirable_spec.rb +0 -1
  138. data/spec/lib/models/revocable_spec.rb +27 -4
  139. data/spec/lib/oauth/authorization/uri_builder_spec.rb +1 -2
  140. data/spec/lib/oauth/authorization_code_request_spec.rb +55 -12
  141. data/spec/lib/oauth/base_request_spec.rb +155 -0
  142. data/spec/lib/oauth/base_response_spec.rb +45 -0
  143. data/spec/lib/oauth/client/credentials_spec.rb +45 -2
  144. data/spec/lib/oauth/client_credentials/creator_spec.rb +1 -1
  145. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  146. data/spec/lib/oauth/client_credentials_request_spec.rb +1 -0
  147. data/spec/lib/oauth/code_request_spec.rb +1 -3
  148. data/spec/lib/oauth/code_response_spec.rb +34 -0
  149. data/spec/lib/oauth/error_response_spec.rb +9 -9
  150. data/spec/lib/oauth/error_spec.rb +1 -1
  151. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -1
  152. data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
  153. data/spec/lib/oauth/password_access_token_request_spec.rb +14 -8
  154. data/spec/lib/oauth/pre_authorization_spec.rb +12 -7
  155. data/spec/lib/oauth/refresh_token_request_spec.rb +52 -9
  156. data/spec/lib/oauth/scopes_spec.rb +28 -2
  157. data/spec/lib/oauth/token_request_spec.rb +6 -8
  158. data/spec/lib/oauth/token_spec.rb +12 -5
  159. data/spec/lib/server_spec.rb +10 -3
  160. data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
  161. data/spec/models/doorkeeper/access_token_spec.rb +116 -48
  162. data/spec/models/doorkeeper/application_spec.rb +145 -29
  163. data/spec/requests/applications/applications_request_spec.rb +5 -5
  164. data/spec/requests/endpoints/authorization_spec.rb +5 -6
  165. data/spec/requests/endpoints/token_spec.rb +8 -1
  166. data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
  167. data/spec/requests/flows/authorization_code_spec.rb +6 -13
  168. data/spec/requests/flows/client_credentials_spec.rb +29 -1
  169. data/spec/requests/flows/implicit_grant_errors_spec.rb +2 -2
  170. data/spec/requests/flows/password_spec.rb +118 -15
  171. data/spec/requests/flows/refresh_token_spec.rb +89 -19
  172. data/spec/requests/flows/revoke_token_spec.rb +105 -91
  173. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  174. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  175. data/spec/routing/custom_controller_routes_spec.rb +4 -0
  176. data/spec/routing/default_routes_spec.rb +5 -1
  177. data/spec/spec_helper.rb +2 -0
  178. data/spec/spec_helper_integration.rb +22 -4
  179. data/spec/support/dependencies/factory_girl.rb +2 -2
  180. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  181. data/spec/support/helpers/model_helper.rb +34 -7
  182. data/spec/support/helpers/request_spec_helper.rb +17 -5
  183. data/spec/support/helpers/url_helper.rb +9 -8
  184. data/spec/support/http_method_shim.rb +38 -0
  185. data/spec/support/shared/controllers_shared_context.rb +15 -10
  186. data/spec/support/shared/models_shared_examples.rb +5 -5
  187. data/spec/validators/redirect_uri_validator_spec.rb +51 -6
  188. data/spec/version/version_spec.rb +15 -0
  189. metadata +128 -46
  190. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  191. data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
  192. data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
  193. data/spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb +0 -41
  194. data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
  195. data/spec/lib/oauth/client/methods_spec.rb +0 -54
@@ -6,137 +6,151 @@ describe 'Revoke Token Flow' do
6
6
  end
7
7
 
8
8
  context 'with default parameters' do
9
- let(:client_application) { FactoryGirl.create :application }
9
+ let(:client_application) { FactoryBot.create :application }
10
10
  let(:resource_owner) { User.create!(name: 'John', password: 'sekret') }
11
- let(:authorization_access_token) do
12
- FactoryGirl.create(:access_token,
11
+ let(:access_token) do
12
+ FactoryBot.create(:access_token,
13
13
  application: client_application,
14
14
  resource_owner_id: resource_owner.id,
15
15
  use_refresh_token: true)
16
16
  end
17
- let(:headers) { { 'HTTP_AUTHORIZATION' => "Bearer #{authorization_access_token.token}" } }
18
17
 
19
- context 'With invalid token to revoke' do
20
- it 'client wants to revoke the given access token' do
21
- post revocation_token_endpoint_url, { token: 'I_AM_AN_INVALIDE_TOKEN' }, headers
18
+ context 'with authenticated, confidential OAuth 2.0 client/application' do
19
+ let(:headers) do
20
+ client_id = client_application.uid
21
+ client_secret = client_application.secret
22
+ credentials = Base64.encode64("#{client_id}:#{client_secret}")
23
+ { 'HTTP_AUTHORIZATION' => "Basic #{credentials}" }
24
+ end
25
+
26
+ it 'should revoke the access token provided' do
27
+ post revocation_token_endpoint_url, { token: access_token.token }, headers
28
+
29
+ access_token.reload
22
30
 
23
- authorization_access_token.reload
24
- # The authorization server responds with HTTP status code 200 if the token
25
- # has been revoked successfully or if the client submitted an invalid token.
26
- expect(response).to be_success
27
- expect(authorization_access_token).to_not be_revoked
31
+ expect(response).to be_successful
32
+ expect(access_token.revoked?).to be_truthy
28
33
  end
29
- end
30
34
 
31
- context 'The access token to revoke is the same than the authorization access token' do
32
- let(:token_to_revoke) { authorization_access_token }
35
+ it 'should revoke the refresh token provided' do
36
+ post revocation_token_endpoint_url, { token: access_token.refresh_token }, headers
37
+
38
+ access_token.reload
33
39
 
34
- it 'client wants to revoke the given access token' do
35
- post revocation_token_endpoint_url, { token: token_to_revoke.token }, headers
40
+ expect(response).to be_successful
41
+ expect(access_token.revoked?).to be_truthy
42
+ end
36
43
 
37
- token_to_revoke.reload
38
- authorization_access_token.reload
44
+ context 'with invalid token to revoke' do
45
+ it 'should not revoke any tokens and respond successfully' do
46
+ num_prev_revoked_tokens = Doorkeeper::AccessToken.where(revoked_at: nil).count
47
+ post revocation_token_endpoint_url, { token: 'I_AM_AN_INVALID_TOKEN' }, headers
39
48
 
40
- expect(response).to be_success
41
- expect(token_to_revoke.revoked?).to be_truthy
42
- expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_truthy
49
+ # The authorization server responds with HTTP status code 200 even if
50
+ # token is invalid
51
+ expect(response).to be_successful
52
+ expect(Doorkeeper::AccessToken.where(revoked_at: nil).count).to eq(num_prev_revoked_tokens)
53
+ end
43
54
  end
44
55
 
45
- it 'client wants to revoke the given access token using the POST query string' do
46
- url_with_query_string = revocation_token_endpoint_url + '?' + Rack::Utils.build_query(token: token_to_revoke.token)
47
- post url_with_query_string, {}, headers
56
+ context 'with bad credentials and a valid token' do
57
+ let(:headers) do
58
+ client_id = client_application.uid
59
+ credentials = Base64.encode64("#{client_id}:poop")
60
+ { 'HTTP_AUTHORIZATION' => "Basic #{credentials}" }
61
+ end
62
+ it 'should not revoke any tokens and respond successfully' do
63
+ post revocation_token_endpoint_url, { token: access_token.token }, headers
48
64
 
49
- token_to_revoke.reload
50
- authorization_access_token.reload
65
+ access_token.reload
51
66
 
52
- expect(response).to be_success
53
- expect(token_to_revoke.revoked?).to be_falsey
54
- expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_falsey
55
- expect(authorization_access_token.revoked?).to be_falsey
67
+ expect(response).to be_successful
68
+ expect(access_token.revoked?).to be_falsey
69
+ end
56
70
  end
57
- end
58
71
 
59
- context 'The access token to revoke app and owners are the same than the authorization access token' do
60
- let(:token_to_revoke) do
61
- FactoryGirl.create(:access_token,
62
- application: client_application,
63
- resource_owner_id: resource_owner.id,
64
- use_refresh_token: true)
72
+ context 'with no credentials and a valid token' do
73
+ it 'should not revoke any tokens and respond successfully' do
74
+ post revocation_token_endpoint_url, { token: access_token.token }
75
+
76
+ access_token.reload
77
+
78
+ expect(response).to be_successful
79
+ expect(access_token.revoked?).to be_falsey
80
+ end
65
81
  end
66
82
 
67
- it 'client wants to revoke the given access token' do
68
- post revocation_token_endpoint_url, { token: token_to_revoke.token }, headers
83
+ context 'with valid token for another client application' do
84
+ let(:other_client_application) { FactoryBot.create :application }
85
+ let(:headers) do
86
+ client_id = other_client_application.uid
87
+ client_secret = other_client_application.secret
88
+ credentials = Base64.encode64("#{client_id}:#{client_secret}")
89
+ { 'HTTP_AUTHORIZATION' => "Basic #{credentials}" }
90
+ end
69
91
 
70
- token_to_revoke.reload
71
- authorization_access_token.reload
92
+ it 'should not revoke the token as its unauthorized' do
93
+ post revocation_token_endpoint_url, { token: access_token.token }, headers
72
94
 
73
- expect(response).to be_success
74
- expect(token_to_revoke.revoked?).to be_truthy
75
- expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_truthy
76
- expect(authorization_access_token.revoked?).to be_falsey
95
+ access_token.reload
96
+
97
+ expect(response).to be_successful
98
+ expect(access_token.revoked?).to be_falsey
99
+ end
77
100
  end
78
101
  end
79
102
 
80
- context 'The access token to revoke authorization owner is the same than the authorization access token' do
81
- let(:other_client_application) { FactoryGirl.create :application }
82
- let(:token_to_revoke) do
83
- FactoryGirl.create(:access_token,
84
- application: other_client_application,
103
+ context 'with public OAuth 2.0 client/application' do
104
+ let(:access_token) do
105
+ FactoryBot.create(:access_token,
106
+ application: nil,
85
107
  resource_owner_id: resource_owner.id,
86
108
  use_refresh_token: true)
87
109
  end
88
110
 
89
- it 'client wants to revoke the given access token' do
90
- post revocation_token_endpoint_url, { token: token_to_revoke.token }, headers
111
+ it 'should revoke the access token provided' do
112
+ post revocation_token_endpoint_url, { token: access_token.token }
91
113
 
92
- token_to_revoke.reload
93
- authorization_access_token.reload
114
+ access_token.reload
94
115
 
95
- expect(response).to be_success
96
- expect(token_to_revoke.revoked?).to be_falsey
97
- expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_falsey
98
- expect(authorization_access_token.revoked?).to be_falsey
116
+ expect(response).to be_successful
117
+ expect(access_token.revoked?).to be_truthy
99
118
  end
100
- end
101
119
 
102
- context 'The access token to revoke app is the same than the authorization access token' do
103
- let(:other_resource_owner) { User.create!(name: 'Matheo', password: 'pareto') }
104
- let(:token_to_revoke) do
105
- FactoryGirl.create(:access_token,
106
- application: client_application,
107
- resource_owner_id: other_resource_owner.id,
108
- use_refresh_token: true)
120
+ it 'should revoke the refresh token provided' do
121
+ post revocation_token_endpoint_url, { token: access_token.refresh_token }
122
+
123
+ access_token.reload
124
+
125
+ expect(response).to be_successful
126
+ expect(access_token.revoked?).to be_truthy
109
127
  end
110
128
 
111
- it 'client wants to revoke the given access token' do
112
- post revocation_token_endpoint_url, { token: token_to_revoke.token }, headers
129
+ context 'with a valid token issued for a confidential client' do
130
+ let(:access_token) do
131
+ FactoryBot.create(:access_token,
132
+ application: client_application,
133
+ resource_owner_id: resource_owner.id,
134
+ use_refresh_token: true)
135
+ end
113
136
 
114
- token_to_revoke.reload
115
- authorization_access_token.reload
137
+ it 'should not revoke the access token provided' do
138
+ post revocation_token_endpoint_url, { token: access_token.token }
116
139
 
117
- expect(response).to be_success
118
- expect(token_to_revoke.revoked?).to be_falsey
119
- expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_falsey
120
- expect(authorization_access_token.revoked?).to be_falsey
121
- end
122
- end
140
+ access_token.reload
123
141
 
124
- context 'With valid refresh token to revoke' do
125
- let(:token_to_revoke) do
126
- FactoryGirl.create(:access_token,
127
- application: client_application,
128
- resource_owner_id: resource_owner.id,
129
- use_refresh_token: true)
130
- end
142
+ expect(response).to be_successful
143
+ expect(access_token.revoked?).to be_falsey
144
+ end
145
+
146
+ it 'should not revoke the refresh token provided' do
147
+ post revocation_token_endpoint_url, { token: access_token.token }
131
148
 
132
- it 'client wants to revoke the given refresh token' do
133
- post revocation_token_endpoint_url, { token: token_to_revoke.refresh_token, token_type_hint: 'refresh_token' }, headers
134
- authorization_access_token.reload
135
- token_to_revoke.reload
149
+ access_token.reload
136
150
 
137
- expect(response).to be_success
138
- expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_truthy
139
- expect(authorization_access_token).to_not be_revoked
151
+ expect(response).to be_successful
152
+ expect(access_token.revoked?).to be_falsey
153
+ end
140
154
  end
141
155
  end
142
156
  end
@@ -2,7 +2,7 @@ require 'spec_helper_integration'
2
2
 
3
3
  describe 'ActionController::Metal API' do
4
4
  before do
5
- @client = FactoryGirl.create(:application)
5
+ @client = FactoryBot.create(:application)
6
6
  @resource = User.create!(name: 'Joe', password: 'sekret')
7
7
  @token = client_is_authorized(@client, @resource)
8
8
  end
@@ -2,7 +2,7 @@ require 'spec_helper_integration'
2
2
 
3
3
  feature 'Private API' do
4
4
  background do
5
- @client = FactoryGirl.create(:application)
5
+ @client = FactoryBot.create(:application)
6
6
  @resource = User.create!(name: 'Joe', password: 'sekret')
7
7
  @token = client_is_authorized(@client, @resource)
8
8
  end
@@ -45,6 +45,10 @@ describe 'Custom controller for routes' do
45
45
  expect(post('/space/oauth/revoke')).to route_to('custom_authorizations#revoke')
46
46
  end
47
47
 
48
+ it 'POST /space/oauth/introspect routes to tokens controller' do
49
+ expect(post('/space/oauth/introspect')).to route_to('custom_authorizations#introspect')
50
+ end
51
+
48
52
  it 'GET /space/oauth/applications routes to applications controller' do
49
53
  expect(get('/space/oauth/applications')).to route_to('custom_authorizations#index')
50
54
  end
@@ -21,6 +21,10 @@ describe 'Default routes' do
21
21
  expect(post('/oauth/revoke')).to route_to('doorkeeper/tokens#revoke')
22
22
  end
23
23
 
24
+ it 'POST /oauth/introspect routes to tokens controller' do
25
+ expect(post('/oauth/introspect')).to route_to('doorkeeper/tokens#introspect')
26
+ end
27
+
24
28
  it 'GET /oauth/applications routes to applications controller' do
25
29
  expect(get('/oauth/applications')).to route_to('doorkeeper/applications#index')
26
30
  end
@@ -29,7 +33,7 @@ describe 'Default routes' do
29
33
  expect(get('/oauth/authorized_applications')).to route_to('doorkeeper/authorized_applications#index')
30
34
  end
31
35
 
32
- it 'GET /oauth/token/info route to authorzed tokeninfo controller' do
36
+ it 'GET /oauth/token/info route to authorized tokeninfo controller' do
33
37
  expect(get('/oauth/token/info')).to route_to('doorkeeper/token_info#show')
34
38
  end
35
39
  end
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,4 @@
1
1
  $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '../lib'))
2
2
  $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '../app'))
3
+
4
+ require 'doorkeeper'
@@ -1,3 +1,19 @@
1
+ if ENV['TRAVIS']
2
+ require 'coveralls'
3
+
4
+ Coveralls.wear!('rails') do
5
+ add_filter('/spec/')
6
+ add_filter('/lib/generators/doorkeeper/templates/')
7
+ end
8
+ else
9
+ require 'simplecov'
10
+
11
+ SimpleCov.start do
12
+ add_filter('/spec/')
13
+ add_filter('/lib/generators/doorkeeper/templates/')
14
+ end
15
+ end
16
+
1
17
  ENV['RAILS_ENV'] ||= 'test'
2
18
  TABLE_NAME_PREFIX = ENV['table_name_prefix'] || nil
3
19
  TABLE_NAME_SUFFIX = ENV['table_name_suffix'] || nil
@@ -11,7 +27,6 @@ require 'capybara/rspec'
11
27
  require 'dummy/config/environment'
12
28
  require 'rspec/rails'
13
29
  require 'generator_spec/test_case'
14
- require 'timecop'
15
30
  require 'database_cleaner'
16
31
 
17
32
  # Load JRuby SQLite3 if in that platform
@@ -21,10 +36,10 @@ begin
21
36
  rescue LoadError
22
37
  end
23
38
 
24
- Rails.logger.info "====> Doorkeeper.orm = #{Doorkeeper.configuration.orm.inspect}"
39
+ Rails.logger.info "====> Doorkeeper.orm = #{Doorkeeper.configuration.orm}"
25
40
  if Doorkeeper.configuration.orm == :active_record
26
- Rails.logger.info "======> active_record.table_name_prefix = #{Rails.configuration.active_record.table_name_prefix.inspect}"
27
- Rails.logger.info "======> active_record.table_name_suffix = #{Rails.configuration.active_record.table_name_suffix.inspect}"
41
+ Rails.logger.info "======> active_record.table_name_prefix = #{Rails.configuration.active_record.table_name_prefix}"
42
+ Rails.logger.info "======> active_record.table_name_suffix = #{Rails.configuration.active_record.table_name_suffix}"
28
43
  end
29
44
  Rails.logger.info "====> Rails version: #{Rails.version}"
30
45
  Rails.logger.info "====> Ruby version: #{RUBY_VERSION}"
@@ -35,6 +50,9 @@ ENGINE_RAILS_ROOT = File.join(File.dirname(__FILE__), '../')
35
50
 
36
51
  Dir["#{File.dirname(__FILE__)}/support/{dependencies,helpers,shared}/*.rb"].each { |f| require f }
37
52
 
53
+ # Remove after dropping support of Rails 4.2
54
+ require "#{File.dirname(__FILE__)}/support/http_method_shim.rb"
55
+
38
56
  RSpec.configure do |config|
39
57
  config.infer_spec_type_from_file_location!
40
58
  config.mock_with :rspec
@@ -1,2 +1,2 @@
1
- require 'factory_girl'
2
- FactoryGirl.find_definitions
1
+ require 'factory_bot'
2
+ FactoryBot.find_definitions
@@ -4,7 +4,7 @@ module AccessTokenRequestHelper
4
4
  application: client,
5
5
  resource_owner_id: resource_owner.id
6
6
  }.merge(access_token_attributes)
7
- FactoryGirl.create(:access_token, attributes)
7
+ FactoryBot.create(:access_token, attributes)
8
8
  end
9
9
  end
10
10
 
@@ -1,6 +1,6 @@
1
1
  module ModelHelper
2
2
  def client_exists(client_attributes = {})
3
- @client = FactoryGirl.create(:application, client_attributes)
3
+ @client = FactoryBot.create(:application, client_attributes)
4
4
  end
5
5
 
6
6
  def create_resource_owner
@@ -8,19 +8,25 @@ module ModelHelper
8
8
  end
9
9
 
10
10
  def authorization_code_exists(options = {})
11
- @authorization = FactoryGirl.create(:access_grant, options)
11
+ @authorization = FactoryBot.create(:access_grant, options)
12
12
  end
13
13
 
14
14
  def access_grant_should_exist_for(client, resource_owner)
15
15
  grant = Doorkeeper::AccessGrant.first
16
- expect(grant.application).to eq(client)
17
- grant.resource_owner_id == resource_owner.id
16
+
17
+ expect(grant.application).to have_attributes(id: client.id).
18
+ and(be_instance_of(Doorkeeper::Application))
19
+
20
+ expect(grant.resource_owner_id).to eq(resource_owner.id)
18
21
  end
19
22
 
20
23
  def access_token_should_exist_for(client, resource_owner)
21
- grant = Doorkeeper::AccessToken.first
22
- expect(grant.application).to eq(client)
23
- grant.resource_owner_id == resource_owner.id
24
+ token = Doorkeeper::AccessToken.first
25
+
26
+ expect(token.application).to have_attributes(id: client.id).
27
+ and(be_instance_of(Doorkeeper::Application))
28
+
29
+ expect(token.resource_owner_id).to eq(resource_owner.id)
24
30
  end
25
31
 
26
32
  def access_grant_should_not_exist
@@ -40,6 +46,27 @@ module ModelHelper
40
46
  grant = Doorkeeper::AccessToken.last
41
47
  expect(grant.scopes).to eq(Doorkeeper::OAuth::Scopes.from_array(args))
42
48
  end
49
+
50
+ def uniqueness_error
51
+ case DOORKEEPER_ORM
52
+ when :active_record
53
+ ActiveRecord::RecordNotUnique
54
+ when :sequel
55
+ error_classes = [Sequel::UniqueConstraintViolation, Sequel::ValidationFailed]
56
+ proc { |error| expect(error.class).to be_in(error_classes) }
57
+ when :mongo_mapper
58
+ error_classes = [MongoMapper::DocumentNotValid, Mongo::OperationFailure]
59
+ proc { |error| expect(error.class).to be_in(error_classes) }
60
+ when /mongoid/
61
+ error_classes = [Mongoid::Errors::Validations]
62
+ error_classes << Moped::Errors::OperationFailure if defined?(::Moped) # Mongoid 4
63
+ error_classes << Mongo::Error::OperationFailure if defined?(::Mongo) # Mongoid 5
64
+
65
+ proc { |error| expect(error.class).to be_in(error_classes) }
66
+ else
67
+ raise "'#{DOORKEEPER_ORM}' ORM is not supported!"
68
+ end
69
+ end
43
70
  end
44
71
 
45
72
  RSpec.configuration.send :include, ModelHelper
@@ -27,6 +27,14 @@ module RequestSpecHelper
27
27
  URI.parse(page.current_url)
28
28
  end
29
29
 
30
+ def request_response
31
+ respond_to?(:response) ? response : page.driver.response
32
+ end
33
+
34
+ def json_response
35
+ JSON.parse(request_response.body)
36
+ end
37
+
30
38
  def should_have_header(header, value)
31
39
  expect(headers[header]).to eq(value)
32
40
  end
@@ -44,15 +52,15 @@ module RequestSpecHelper
44
52
  end
45
53
 
46
54
  def should_have_json(key, value)
47
- expect(JSON.parse(response.body).fetch(key)).to eq(value)
55
+ expect(json_response.fetch(key)).to eq(value)
48
56
  end
49
57
 
50
58
  def should_have_json_within(key, value, range)
51
- expect(JSON.parse(response.body).fetch(key)).to be_within(range).of(value)
59
+ expect(json_response.fetch(key)).to be_within(range).of(value)
52
60
  end
53
61
 
54
62
  def should_not_have_json(key)
55
- expect(JSON.parse(response.body)).not_to have_key(key)
63
+ expect(json_response).not_to have_key(key)
56
64
  end
57
65
 
58
66
  def sign_in
@@ -60,16 +68,20 @@ module RequestSpecHelper
60
68
  click_on 'Sign in'
61
69
  end
62
70
 
71
+ def create_access_token(authorization_code, client)
72
+ page.driver.post token_endpoint_url(code: authorization_code, client: client)
73
+ end
74
+
63
75
  def i_should_see_translated_error_message(key)
64
76
  i_should_see translated_error_message(key)
65
77
  end
66
78
 
67
79
  def translated_error_message(key)
68
- I18n.translate key, scope: [:doorkeeper, :errors, :messages]
80
+ I18n.translate key, scope: %i[doorkeeper errors messages]
69
81
  end
70
82
 
71
83
  def response_status_should_be(status)
72
- expect(page.driver.response.status.to_i).to eq(status)
84
+ expect(request_response.status.to_i).to eq(status)
73
85
  end
74
86
  end
75
87
 
@@ -2,10 +2,10 @@ module UrlHelper
2
2
  def token_endpoint_url(options = {})
3
3
  parameters = {
4
4
  code: options[:code],
5
- client_id: options[:client_id] || (options[:client] ? options[:client].uid : nil),
5
+ client_id: options[:client_id] || (options[:client] ? options[:client].uid : nil),
6
6
  client_secret: options[:client_secret] || (options[:client] ? options[:client].secret : nil),
7
7
  redirect_uri: options[:redirect_uri] || (options[:client] ? options[:client].redirect_uri : nil),
8
- grant_type: options[:grant_type] || 'authorization_code'
8
+ grant_type: options[:grant_type] || 'authorization_code'
9
9
  }
10
10
  "/oauth/token?#{build_query(parameters)}"
11
11
  end
@@ -13,10 +13,11 @@ module UrlHelper
13
13
  def password_token_endpoint_url(options = {})
14
14
  parameters = {
15
15
  code: options[:code],
16
- client_id: options[:client_id] || (options[:client] ? options[:client].uid : nil),
16
+ client_id: options[:client_id] || (options[:client] ? options[:client].uid : nil),
17
17
  client_secret: options[:client_secret] || (options[:client] ? options[:client].secret : nil),
18
18
  username: options[:resource_owner_username] || (options[:resource_owner] ? options[:resource_owner].name : nil),
19
19
  password: options[:resource_owner_password] || (options[:resource_owner] ? options[:resource_owner].password : nil),
20
+ scope: options[:scope],
20
21
  grant_type: 'password'
21
22
  }
22
23
  "/oauth/token?#{build_query(parameters)}"
@@ -24,21 +25,21 @@ module UrlHelper
24
25
 
25
26
  def authorization_endpoint_url(options = {})
26
27
  parameters = {
27
- client_id: options[:client_id] || options[:client].uid,
28
- redirect_uri: options[:redirect_uri] || options[:client].redirect_uri,
28
+ client_id: options[:client_id] || options[:client].uid,
29
+ redirect_uri: options[:redirect_uri] || options[:client].redirect_uri,
29
30
  response_type: options[:response_type] || 'code',
30
31
  scope: options[:scope],
31
32
  state: options[:state]
32
- }.reject { |k, v| v.blank? }
33
+ }.reject { |_, v| v.blank? }
33
34
  "/oauth/authorize?#{build_query(parameters)}"
34
35
  end
35
36
 
36
37
  def refresh_token_endpoint_url(options = {})
37
38
  parameters = {
38
39
  refresh_token: options[:refresh_token],
39
- client_id: options[:client_id] || options[:client].uid,
40
+ client_id: options[:client_id] || options[:client].uid,
40
41
  client_secret: options[:client_secret] || options[:client].secret,
41
- grant_type: options[:grant_type] || 'refresh_token'
42
+ grant_type: options[:grant_type] || 'refresh_token'
42
43
  }
43
44
  "/oauth/token?#{build_query(parameters)}"
44
45
  end
@@ -0,0 +1,38 @@
1
+ # Rails 5 deprecates calling HTTP action methods with positional arguments
2
+ # in favor of keyword arguments. However, the keyword argument form is only
3
+ # supported in Rails 5+. Since we support back to 4, we need some sort of shim
4
+ # to avoid super noisy deprecations when running tests.
5
+ module RoutingHTTPMethodShim
6
+ def get(path, params = {}, headers = nil)
7
+ super(path, params: params, headers: headers)
8
+ end
9
+
10
+ def post(path, params = {}, headers = nil)
11
+ super(path, params: params, headers: headers)
12
+ end
13
+
14
+ def put(path, params = {}, headers = nil)
15
+ super(path, params: params, headers: headers)
16
+ end
17
+ end
18
+
19
+ module ControllerHTTPMethodShim
20
+ def get(path, params = {})
21
+ super(path, params: params)
22
+ end
23
+
24
+ def post(path, params = {})
25
+ super(path, params: params)
26
+ end
27
+
28
+ def put(path, params = {})
29
+ super(path, params: params)
30
+ end
31
+ end
32
+
33
+ if ::Rails::VERSION::MAJOR >= 5
34
+ RSpec.configure do |config|
35
+ config.include ControllerHTTPMethodShim, type: :controller
36
+ config.include RoutingHTTPMethodShim, type: :request
37
+ end
38
+ end
@@ -1,28 +1,33 @@
1
1
  shared_context 'valid token', token: :valid do
2
- let :token_string do
3
- '1A2B3C4D'
4
- end
2
+ let(:token_string) { '1A2B3C4D' }
5
3
 
6
4
  let :token do
7
- double(Doorkeeper::AccessToken, accessible?: true, includes_scope?: true, acceptable?: true)
5
+ double(Doorkeeper::AccessToken,
6
+ accessible?: true, includes_scope?: true, acceptable?: true,
7
+ previous_refresh_token: "", revoke_previous_refresh_token!: true)
8
8
  end
9
9
 
10
10
  before :each do
11
- allow(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token)
11
+ allow(
12
+ Doorkeeper::AccessToken
13
+ ).to receive(:by_token).with(token_string).and_return(token)
12
14
  end
13
15
  end
14
16
 
15
17
  shared_context 'invalid token', token: :invalid do
16
- let :token_string do
17
- '1A2B3C4D'
18
- end
18
+ let(:token_string) { '1A2B3C4D' }
19
19
 
20
20
  let :token do
21
- double(Doorkeeper::AccessToken, accessible?: false, revoked?: false, expired?: false, includes_scope?: false, acceptable?: false)
21
+ double(Doorkeeper::AccessToken,
22
+ accessible?: false, revoked?: false, expired?: false,
23
+ includes_scope?: false, acceptable?: false,
24
+ previous_refresh_token: "", revoke_previous_refresh_token!: true)
22
25
  end
23
26
 
24
27
  before :each do
25
- allow(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token)
28
+ allow(
29
+ Doorkeeper::AccessToken
30
+ ).to receive(:by_token).with(token_string).and_return(token)
26
31
  end
27
32
  end
28
33
 
@@ -34,19 +34,19 @@ shared_examples 'a unique token' do
34
34
  end
35
35
 
36
36
  it 'is not valid if token exists' do
37
- token1 = FactoryGirl.create factory_name
38
- token2 = FactoryGirl.create factory_name
37
+ token1 = FactoryBot.create factory_name
38
+ token2 = FactoryBot.create factory_name
39
39
  token2.token = token1.token
40
40
  expect(token2).not_to be_valid
41
41
  end
42
42
 
43
43
  it 'expects database to throw an error when tokens are the same' do
44
- token1 = FactoryGirl.create factory_name
45
- token2 = FactoryGirl.create factory_name
44
+ token1 = FactoryBot.create factory_name
45
+ token2 = FactoryBot.create factory_name
46
46
  token2.token = token1.token
47
47
  expect do
48
48
  token2.save!(validate: false)
49
- end.to raise_error(ActiveRecord::RecordNotUnique)
49
+ end.to raise_error(uniqueness_error)
50
50
  end
51
51
  end
52
52
  end