doorkeeper-sequel 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +13 -0
  6. data/.travis.yml +24 -0
  7. data/CHANGELOG.md +24 -0
  8. data/Gemfile +23 -0
  9. data/Gemfile.lock +172 -0
  10. data/LICENSE +21 -0
  11. data/README.md +76 -0
  12. data/Rakefile +56 -0
  13. data/config/locales/en.yml +16 -0
  14. data/doorkeeper-sequel.gemspec +32 -0
  15. data/gemfiles/rails-4.2.gemfile +11 -0
  16. data/gemfiles/rails-5.0.gemfile +11 -0
  17. data/lib/doorkeeper/orm/sequel/access_grant.rb +9 -0
  18. data/lib/doorkeeper/orm/sequel/access_token.rb +32 -0
  19. data/lib/doorkeeper/orm/sequel/application.rb +18 -0
  20. data/lib/doorkeeper/orm/sequel/models/access_grant_mixin.rb +50 -0
  21. data/lib/doorkeeper/orm/sequel/models/access_token_mixin.rb +163 -0
  22. data/lib/doorkeeper/orm/sequel/models/application_mixin.rb +70 -0
  23. data/lib/doorkeeper/orm/sequel/models/concerns/ownership.rb +19 -0
  24. data/lib/doorkeeper/orm/sequel/models/concerns/sequel_compat.rb +40 -0
  25. data/lib/doorkeeper/orm/sequel/validators/redirect_uri_validator.rb +49 -0
  26. data/lib/doorkeeper/orm/sequel.rb +18 -0
  27. data/lib/doorkeeper-sequel/gem_version.rb +13 -0
  28. data/lib/doorkeeper-sequel/version.rb +7 -0
  29. data/lib/doorkeeper-sequel.rb +18 -0
  30. data/lib/generators/doorkeeper/sequel/application_owner_generator.rb +23 -0
  31. data/lib/generators/doorkeeper/sequel/migration_generator.rb +23 -0
  32. data/lib/generators/doorkeeper/sequel/previous_refresh_token_generator.rb +23 -0
  33. data/lib/generators/doorkeeper/sequel/templates/add_owner_to_application.rb +9 -0
  34. data/lib/generators/doorkeeper/sequel/templates/add_previous_refresh_token_to_access_tokens.rb +7 -0
  35. data/lib/generators/doorkeeper/sequel/templates/migration.rb +59 -0
  36. data/spec/controllers/application_metal_controller.rb +10 -0
  37. data/spec/controllers/applications_controller_spec.rb +58 -0
  38. data/spec/controllers/authorizations_controller_spec.rb +189 -0
  39. data/spec/controllers/protected_resources_controller_spec.rb +300 -0
  40. data/spec/controllers/token_info_controller_spec.rb +52 -0
  41. data/spec/controllers/tokens_controller_spec.rb +88 -0
  42. data/spec/dummy/Rakefile +7 -0
  43. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  44. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +7 -0
  45. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +12 -0
  46. data/spec/dummy/app/controllers/home_controller.rb +17 -0
  47. data/spec/dummy/app/controllers/metal_controller.rb +11 -0
  48. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +11 -0
  49. data/spec/dummy/app/helpers/application_helper.rb +5 -0
  50. data/spec/dummy/app/models/user.rb +11 -0
  51. data/spec/dummy/app/views/home/index.html.erb +0 -0
  52. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  53. data/spec/dummy/config/application.rb +29 -0
  54. data/spec/dummy/config/boot.rb +9 -0
  55. data/spec/dummy/config/database.yml +15 -0
  56. data/spec/dummy/config/environment.rb +5 -0
  57. data/spec/dummy/config/environments/development.rb +29 -0
  58. data/spec/dummy/config/environments/production.rb +62 -0
  59. data/spec/dummy/config/environments/test.rb +44 -0
  60. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  61. data/spec/dummy/config/initializers/db.rb +74 -0
  62. data/spec/dummy/config/initializers/doorkeeper.rb +96 -0
  63. data/spec/dummy/config/initializers/secret_token.rb +9 -0
  64. data/spec/dummy/config/initializers/session_store.rb +8 -0
  65. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  66. data/spec/dummy/config/locales/doorkeeper.en.yml +5 -0
  67. data/spec/dummy/config/routes.rb +52 -0
  68. data/spec/dummy/config.ru +4 -0
  69. data/spec/dummy/db/migrate/20111122132257_create_users.rb +9 -0
  70. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +5 -0
  71. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +60 -0
  72. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +7 -0
  73. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +11 -0
  74. data/spec/dummy/db/schema.rb +67 -0
  75. data/spec/dummy/log/test.log +19813 -0
  76. data/spec/dummy/public/404.html +26 -0
  77. data/spec/dummy/public/422.html +26 -0
  78. data/spec/dummy/public/500.html +26 -0
  79. data/spec/dummy/public/favicon.ico +0 -0
  80. data/spec/dummy/script/rails +6 -0
  81. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-T/-TZF6Ae6YipbyKuHghb9wlTx4_b9itbSHRc_2PmqjiU.cache +1 -0
  82. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/0p/0pa3wNbGHqFC6gxrMvdOJiP6gPwFv9VJ_npjEfRWxAE.cache +1 -0
  83. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2e/2eYh115US2lIRhM2KTEaJFa6aV_cX8iv6JAdjuq0Uio.cache +1 -0
  84. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3P/3PoguHEOEeItUjmwC74MWLLP-_Ijow7798bF5U6K2dw.cache +1 -0
  85. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/6b/6b0anrSo7Fvoc05t4Ca0zZmfS_cpERy1DsG3ea6lBOg.cache +0 -0
  86. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/BA/BAC3ZaGoeZ9Od-kKg-UQYelvRgsCa0H72-52nLdcTNw.cache +1 -0
  87. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Bw/Bw6Nimjvy5Yv1AYbZb1t-v0eMNhv-bhwBzR-b5mY7FU.cache +0 -0
  88. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Fq/FqQWjMAz8yjZQlMC_dUsztaOxGruI2IXyGAAUF9SvQ0.cache +1 -0
  89. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/J_/J_D9clwKidN28hnVB1O3zEfKDwg90Usdb5ToKiPq_aw.cache +0 -0
  90. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ji/JitNKkP1dYdu9ObSdIkkEAsiFxEmRO5oy1UIyhT_hYs.cache +0 -0
  91. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Jq/JqTLVvnY2AgGkHftWPwqt_HkbwhYRsmgHxk37VqKJAY.cache +0 -0
  92. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QX/QXcp8DweOJ6BfMedGMfeHvVXv2hjDIleln1LSJk7vOE.cache +2 -0
  93. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Qy/Qy1ldbz6vKa_fv4E4ByxWslKFoV1qReQR5DKJ525z88.cache +1 -0
  94. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rl/RlCJ_X5xFsE3VBDhkYrY7r_R6sMgiAc03cT8nr7Q2vY.cache +0 -0
  95. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ta/TaYxNn81MhqC3DnMC6_y_Q7xap5Ntn4ggFo94EUaiak.cache +0 -0
  96. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Wq/WqbLVKOcTMZtttygYt_ncr1mGIDrzevSTaPGNmzV1D8.cache +1 -0
  97. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/YF/YF60qiQ28QMoYDrLmrbHWZr7X7bl5MxVPR5QrrVCFak.cache +1 -0
  98. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Yf/YfJJZvm_NONHd4eCasDibCcRapZ_WYIO5MUxSUUbYFk.cache +0 -0
  99. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Z0/Z0e47cT2a-21U-w-3gkbgqC3o5jWnEzOB8vW06aJH1E.cache +0 -0
  100. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/_u/_uy-z8SVnhffUNelRxbPDL2aAUPb_GbqREXVsfy8uGc.cache +0 -0
  101. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/dL/dL7SLUWUIeVdyA1UuH-rvif0nzesOar3LdEtqzdb4bE.cache +0 -0
  102. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/f8/f8WT8jqR1qNIdQaRDpXbyLN7E5AWkbYFBwdh9Ozk7gk.cache +1 -0
  103. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/hk/hk2YB6skvc72qL4IzzQKU8Emyfe5vARjoD1bvQTw4zE.cache +1 -0
  104. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/iO/iOpDp_7ZvBNO5WIpTmqNewUl9bB2satqXWulyNvAaX8.cache +0 -0
  105. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ii/iiJRBZIsxKiwyzU_Z7UtQeUTXMRJRPTreTKRvAWO7_8.cache +1 -0
  106. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mj/mjuMepngMLrtgilLlJ9oTTSqoGO1YUww1rXphQ1pOm4.cache +0 -0
  107. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qo/qo6SpT75QykYB63Aqq5bgzpXyNU1Y4dGFvCCJgoWQpE.cache +1 -0
  108. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sp/sprzBMBliJDI__s-0D3q82tn1MpBkFV0N651hTr3XE8.cache +1 -0
  109. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/tM/tM6A7CR8QluP_u4u59vN1GjSZGNqNH3TXkkNzb9EPXA.cache +0 -0
  110. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/vO/vOXN0mER62j4JiPpMTSVS7MMqs0067cZx14vD5B8qiQ.cache +0 -0
  111. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zz/zzlQ_kom0liFOvGYDcjtVw6yAHOyA-bbzP8f0e_Tq1A.cache +1 -0
  112. data/spec/factories.rb +28 -0
  113. data/spec/generators/application_owner_generator_spec.rb +20 -0
  114. data/spec/generators/migration_generator_spec.rb +20 -0
  115. data/spec/generators/previous_refresh_token_generator_spec.rb +20 -0
  116. data/spec/generators/templates/routes.rb +3 -0
  117. data/spec/generators/tmp/dummy/db/migrate/20161012132809_create_doorkeeper_tables.rb +59 -0
  118. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +24 -0
  119. data/spec/lib/config_spec.rb +334 -0
  120. data/spec/lib/doorkeeper_spec.rb +28 -0
  121. data/spec/lib/models/expirable_spec.rb +51 -0
  122. data/spec/lib/models/revocable_spec.rb +59 -0
  123. data/spec/lib/models/scopes_spec.rb +43 -0
  124. data/spec/lib/oauth/authorization/uri_builder_spec.rb +42 -0
  125. data/spec/lib/oauth/authorization_code_request_spec.rb +80 -0
  126. data/spec/lib/oauth/client/credentials_spec.rb +47 -0
  127. data/spec/lib/oauth/client/methods_spec.rb +54 -0
  128. data/spec/lib/oauth/client_credentials/creator_spec.rb +44 -0
  129. data/spec/lib/oauth/client_credentials/issuer_spec.rb +86 -0
  130. data/spec/lib/oauth/client_credentials/validation_spec.rb +54 -0
  131. data/spec/lib/oauth/client_credentials_integration_spec.rb +27 -0
  132. data/spec/lib/oauth/client_credentials_request_spec.rb +104 -0
  133. data/spec/lib/oauth/client_spec.rb +39 -0
  134. data/spec/lib/oauth/code_request_spec.rb +45 -0
  135. data/spec/lib/oauth/code_response_spec.rb +34 -0
  136. data/spec/lib/oauth/error_response_spec.rb +61 -0
  137. data/spec/lib/oauth/error_spec.rb +23 -0
  138. data/spec/lib/oauth/forbidden_token_response_spec.rb +23 -0
  139. data/spec/lib/oauth/helpers/scope_checker_spec.rb +64 -0
  140. data/spec/lib/oauth/helpers/unique_token_spec.rb +20 -0
  141. data/spec/lib/oauth/helpers/uri_checker_spec.rb +104 -0
  142. data/spec/lib/oauth/invalid_token_response_spec.rb +28 -0
  143. data/spec/lib/oauth/password_access_token_request_spec.rb +90 -0
  144. data/spec/lib/oauth/pre_authorization_spec.rb +155 -0
  145. data/spec/lib/oauth/refresh_token_request_spec.rb +154 -0
  146. data/spec/lib/oauth/scopes_spec.rb +122 -0
  147. data/spec/lib/oauth/token_request_spec.rb +98 -0
  148. data/spec/lib/oauth/token_response_spec.rb +85 -0
  149. data/spec/lib/oauth/token_spec.rb +116 -0
  150. data/spec/lib/request/strategy_spec.rb +53 -0
  151. data/spec/lib/server_spec.rb +52 -0
  152. data/spec/models/doorkeeper/access_grant_spec.rb +36 -0
  153. data/spec/models/doorkeeper/access_token_spec.rb +394 -0
  154. data/spec/models/doorkeeper/application_spec.rb +179 -0
  155. data/spec/requests/applications/applications_request_spec.rb +94 -0
  156. data/spec/requests/applications/authorized_applications_spec.rb +30 -0
  157. data/spec/requests/endpoints/authorization_spec.rb +72 -0
  158. data/spec/requests/endpoints/token_spec.rb +64 -0
  159. data/spec/requests/flows/authorization_code_errors_spec.rb +66 -0
  160. data/spec/requests/flows/authorization_code_spec.rb +156 -0
  161. data/spec/requests/flows/client_credentials_spec.rb +58 -0
  162. data/spec/requests/flows/implicit_grant_errors_spec.rb +32 -0
  163. data/spec/requests/flows/implicit_grant_spec.rb +61 -0
  164. data/spec/requests/flows/password_spec.rb +115 -0
  165. data/spec/requests/flows/refresh_token_spec.rb +174 -0
  166. data/spec/requests/flows/revoke_token_spec.rb +157 -0
  167. data/spec/requests/flows/skip_authorization_spec.rb +59 -0
  168. data/spec/requests/protected_resources/metal_spec.rb +14 -0
  169. data/spec/requests/protected_resources/private_api_spec.rb +81 -0
  170. data/spec/routing/custom_controller_routes_spec.rb +71 -0
  171. data/spec/routing/default_routes_spec.rb +35 -0
  172. data/spec/routing/scoped_routes_spec.rb +31 -0
  173. data/spec/spec_helper.rb +2 -0
  174. data/spec/spec_helper_integration.rb +50 -0
  175. data/spec/stubs/config/application.rb +29 -0
  176. data/spec/stubs/config/initializers/db.rb +74 -0
  177. data/spec/stubs/generators/application_owner_generator_spec.rb +20 -0
  178. data/spec/stubs/generators/migration_generator_spec.rb +20 -0
  179. data/spec/stubs/generators/previous_refresh_token_generator_spec.rb +20 -0
  180. data/spec/stubs/generators/tmp/dummy/db/migrate/20161012132810_add_owner_to_application.rb +9 -0
  181. data/spec/stubs/models/user.rb +11 -0
  182. data/spec/stubs/spec_helper_integration.rb +50 -0
  183. data/spec/stubs/support/sequel.rb +0 -0
  184. data/spec/support/dependencies/factory_girl.rb +2 -0
  185. data/spec/support/helpers/access_token_request_helper.rb +11 -0
  186. data/spec/support/helpers/authorization_request_helper.rb +41 -0
  187. data/spec/support/helpers/config_helper.rb +9 -0
  188. data/spec/support/helpers/model_helper.rb +67 -0
  189. data/spec/support/helpers/request_spec_helper.rb +76 -0
  190. data/spec/support/helpers/url_helper.rb +55 -0
  191. data/spec/support/http_method_shim.rb +24 -0
  192. data/spec/support/orm/active_record.rb +3 -0
  193. data/spec/support/orm/sequel.rb +0 -0
  194. data/spec/support/shared/controllers_shared_context.rb +69 -0
  195. data/spec/support/shared/models_shared_examples.rb +52 -0
  196. data/spec/validators/redirect_uri_validator_spec.rb +78 -0
  197. metadata +570 -0
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+ require 'uri'
3
+ require 'doorkeeper/oauth/helpers/uri_checker'
4
+
5
+ module Doorkeeper::OAuth::Helpers
6
+ describe URIChecker do
7
+ describe '.valid?' do
8
+ it 'is valid for valid uris' do
9
+ uri = 'http://app.co'
10
+ expect(URIChecker.valid?(uri)).to be_truthy
11
+ end
12
+
13
+ it 'is valid if include path param' do
14
+ uri = 'http://app.co/path'
15
+ expect(URIChecker.valid?(uri)).to be_truthy
16
+ end
17
+
18
+ it 'is valid if include query param' do
19
+ uri = 'http://app.co/?query=1'
20
+ expect(URIChecker.valid?(uri)).to be_truthy
21
+ end
22
+
23
+ it 'is invalid if uri includes fragment' do
24
+ uri = 'http://app.co/test#fragment'
25
+ expect(URIChecker.valid?(uri)).to be_falsey
26
+ end
27
+
28
+ it 'is invalid if scheme is missing' do
29
+ uri = 'app.co'
30
+ expect(URIChecker.valid?(uri)).to be_falsey
31
+ end
32
+
33
+ it 'is invalid if is a relative uri' do
34
+ uri = '/abc/123'
35
+ expect(URIChecker.valid?(uri)).to be_falsey
36
+ end
37
+
38
+ it 'is invalid if is not a url' do
39
+ uri = 'http://'
40
+ expect(URIChecker.valid?(uri)).to be_falsey
41
+ end
42
+ end
43
+
44
+ describe '.matches?' do
45
+ it 'is true if both url matches' do
46
+ uri = client_uri = 'http://app.co/aaa'
47
+ expect(URIChecker.matches?(uri, client_uri)).to be_truthy
48
+ end
49
+
50
+ it 'ignores query parameter on comparsion' do
51
+ uri = 'http://app.co/?query=hello'
52
+ client_uri = 'http://app.co'
53
+ expect(URIChecker.matches?(uri, client_uri)).to be_truthy
54
+ end
55
+
56
+ it 'doesn\'t allow non-matching domains through' do
57
+ uri = 'http://app.abc/?query=hello'
58
+ client_uri = 'http://app.co'
59
+ expect(URIChecker.matches?(uri, client_uri)).to be_falsey
60
+ end
61
+
62
+ it 'doesn\'t allow non-matching domains that don\'t start at the beginning' do
63
+ uri = 'http://app.co/?query=hello'
64
+ client_uri = 'http://example.com?app.co=test'
65
+ expect(URIChecker.matches?(uri, client_uri)).to be_falsey
66
+ end
67
+ end
68
+
69
+ describe '.valid_for_authorization?' do
70
+ it 'is true if valid and matches' do
71
+ uri = client_uri = 'http://app.co/aaa'
72
+ expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be_truthy
73
+ end
74
+
75
+ it 'is false if valid and mismatches' do
76
+ uri = 'http://app.co/aaa'
77
+ client_uri = 'http://app.co/bbb'
78
+ expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be_falsey
79
+ end
80
+
81
+ it 'is true if valid and included in array' do
82
+ uri = 'http://app.co/aaa'
83
+ client_uri = "http://example.com/bbb\nhttp://app.co/aaa"
84
+ expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be_truthy
85
+ end
86
+
87
+ it 'is false if valid and not included in array' do
88
+ uri = 'http://app.co/aaa'
89
+ client_uri = "http://example.com/bbb\nhttp://app.co/cc"
90
+ expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be_falsey
91
+ end
92
+
93
+ it 'is true if valid and matches' do
94
+ uri = client_uri = 'http://app.co/aaa'
95
+ expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be true
96
+ end
97
+
98
+ it 'is false if invalid' do
99
+ uri = client_uri = 'http://app.co/aaa?waffles=abc'
100
+ expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be false
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'active_model'
3
+ require 'doorkeeper'
4
+ require 'doorkeeper/oauth/invalid_token_response'
5
+
6
+ module Doorkeeper::OAuth
7
+ describe InvalidTokenResponse do
8
+ describe '#name' do
9
+ it { expect(subject.name).to eq(:invalid_token) }
10
+ end
11
+
12
+ describe '#status' do
13
+ it { expect(subject.status).to eq(:unauthorized) }
14
+ end
15
+
16
+ describe :from_access_token do
17
+ it 'revoked' do
18
+ response = InvalidTokenResponse.from_access_token double(revoked?: true, expired?: true)
19
+ expect(response.description).to include('revoked')
20
+ end
21
+
22
+ it 'expired' do
23
+ response = InvalidTokenResponse.from_access_token double(revoked?: false, expired?: true)
24
+ expect(response.description).to include('expired')
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper_integration'
2
+
3
+ module Doorkeeper::OAuth
4
+ describe PasswordAccessTokenRequest do
5
+ let(:server) do
6
+ double(
7
+ :server,
8
+ default_scopes: Doorkeeper::OAuth::Scopes.new,
9
+ access_token_expires_in: 2.hours,
10
+ refresh_token_enabled?: false,
11
+ custom_access_token_expires_in: ->(_app) { nil }
12
+ )
13
+ end
14
+ let(:client) { FactoryGirl.create(:application) }
15
+ let(:owner) { double :owner, id: 99 }
16
+
17
+ subject do
18
+ PasswordAccessTokenRequest.new(server, client, owner)
19
+ end
20
+
21
+ it 'issues a new token for the client' do
22
+ expect do
23
+ subject.authorize
24
+ end.to change { client.reload.access_tokens.count }.by(1)
25
+ end
26
+
27
+ it 'issues a new token without a client' do
28
+ expect do
29
+ subject.client = nil
30
+ subject.authorize
31
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
32
+ end
33
+
34
+ it 'does not issue a new token with an invalid client' do
35
+ expect do
36
+ subject.client = nil
37
+ subject.parameters = { client_id: 'bad_id' }
38
+ subject.authorize
39
+ end.to_not change { Doorkeeper::AccessToken.count }
40
+
41
+ expect(subject.error).to eq(:invalid_client)
42
+ end
43
+
44
+ it 'requires the owner' do
45
+ subject.resource_owner = nil
46
+ subject.validate
47
+ expect(subject.error).to eq(:invalid_grant)
48
+ end
49
+
50
+ it 'optionally accepts the client' do
51
+ subject.client = nil
52
+ expect(subject).to be_valid
53
+ end
54
+
55
+ it 'creates token even when there is already one (default)' do
56
+ FactoryGirl.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
57
+ expect do
58
+ subject.authorize
59
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
60
+ end
61
+
62
+ it 'skips token creation if there is already one' do
63
+ allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
64
+ FactoryGirl.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
65
+ expect do
66
+ subject.authorize
67
+ end.to_not change { Doorkeeper::AccessToken.count }
68
+ end
69
+
70
+ describe 'with scopes' do
71
+ subject do
72
+ PasswordAccessTokenRequest.new(server, client, owner, scope: 'public')
73
+ end
74
+
75
+ it 'validates the current scope' do
76
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('another'))
77
+ subject.validate
78
+ expect(subject.error).to eq(:invalid_scope)
79
+ end
80
+
81
+ it 'creates the token with scopes' do
82
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('public'))
83
+ expect do
84
+ subject.authorize
85
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
86
+ expect(Doorkeeper::AccessToken.last.scopes).to include('public')
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,155 @@
1
+ require 'spec_helper_integration'
2
+
3
+ module Doorkeeper::OAuth
4
+ describe PreAuthorization do
5
+ let(:server) {
6
+ server = Doorkeeper.configuration
7
+ allow(server).to receive(:default_scopes).and_return(Scopes.new)
8
+ allow(server).to receive(:scopes).and_return(Scopes.from_string('public profile'))
9
+ server
10
+ }
11
+
12
+ let(:application) do
13
+ application = double :application
14
+ allow(application).to receive(:scopes).and_return(Scopes.from_string(''))
15
+ application
16
+ end
17
+
18
+ let(:client) do
19
+ double :client, redirect_uri: 'http://tst.com/auth', application: application
20
+ end
21
+
22
+ let :attributes do
23
+ {
24
+ response_type: 'code',
25
+ redirect_uri: 'http://tst.com/auth',
26
+ state: 'save-this'
27
+ }
28
+ end
29
+
30
+ subject do
31
+ PreAuthorization.new(server, client, attributes)
32
+ end
33
+
34
+ it 'is authorizable when request is valid' do
35
+ expect(subject).to be_authorizable
36
+ end
37
+
38
+ it 'accepts code as response type' do
39
+ subject.response_type = 'code'
40
+ expect(subject).to be_authorizable
41
+ end
42
+
43
+ it 'accepts token as response type' do
44
+ allow(server).to receive(:grant_flows).and_return(['implicit'])
45
+ subject.response_type = 'token'
46
+ expect(subject).to be_authorizable
47
+ end
48
+
49
+ context 'when using default grant flows' do
50
+ it 'accepts "code" as response type' do
51
+ subject.response_type = 'code'
52
+ expect(subject).to be_authorizable
53
+ end
54
+
55
+ it 'accepts "token" as response type' do
56
+ allow(server).to receive(:grant_flows).and_return(['implicit'])
57
+ subject.response_type = 'token'
58
+ expect(subject).to be_authorizable
59
+ end
60
+ end
61
+
62
+ context 'when authorization code grant flow is disabled' do
63
+ before do
64
+ allow(server).to receive(:grant_flows).and_return(['implicit'])
65
+ end
66
+
67
+ it 'does not accept "code" as response type' do
68
+ subject.response_type = 'code'
69
+ expect(subject).not_to be_authorizable
70
+ end
71
+ end
72
+
73
+ context 'when implicit grant flow is disabled' do
74
+ before do
75
+ allow(server).to receive(:grant_flows).and_return(['authorization_code'])
76
+ end
77
+
78
+ it 'does not accept "token" as response type' do
79
+ subject.response_type = 'token'
80
+ expect(subject).not_to be_authorizable
81
+ end
82
+ end
83
+
84
+ context 'client application does not restrict valid scopes' do
85
+ it 'accepts valid scopes' do
86
+ subject.scope = 'public'
87
+ expect(subject).to be_authorizable
88
+ end
89
+
90
+ it 'rejects (globally) non-valid scopes' do
91
+ subject.scope = 'invalid'
92
+ expect(subject).not_to be_authorizable
93
+ end
94
+ end
95
+
96
+ context 'client application restricts valid scopes' do
97
+ let(:application) do
98
+ application = double :application
99
+ allow(application).to receive(:scopes).and_return(Scopes.from_string('public nonsense'))
100
+ application
101
+ end
102
+
103
+ it 'accepts valid scopes' do
104
+ subject.scope = 'public'
105
+ expect(subject).to be_authorizable
106
+ end
107
+
108
+ it 'rejects (globally) non-valid scopes' do
109
+ subject.scope = 'invalid'
110
+ expect(subject).not_to be_authorizable
111
+ end
112
+
113
+ it 'rejects (application level) non-valid scopes' do
114
+ subject.scope = 'profile'
115
+ expect(subject).to_not be_authorizable
116
+ end
117
+ end
118
+
119
+ it 'uses default scopes when none is required' do
120
+ allow(server).to receive(:default_scopes).and_return(Scopes.from_string('default'))
121
+ subject.scope = nil
122
+ expect(subject.scope).to eq('default')
123
+ expect(subject.scopes).to eq(Scopes.from_string('default'))
124
+ end
125
+
126
+ it 'accepts test uri' do
127
+ subject.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
128
+ expect(subject).to be_authorizable
129
+ end
130
+
131
+ it 'matches the redirect uri against client\'s one' do
132
+ subject.redirect_uri = 'http://nothesame.com'
133
+ expect(subject).not_to be_authorizable
134
+ end
135
+
136
+ it 'stores the state' do
137
+ expect(subject.state).to eq('save-this')
138
+ end
139
+
140
+ it 'rejects if response type is not allowed' do
141
+ subject.response_type = 'whops'
142
+ expect(subject).not_to be_authorizable
143
+ end
144
+
145
+ it 'requires an existing client' do
146
+ subject.client = nil
147
+ expect(subject).not_to be_authorizable
148
+ end
149
+
150
+ it 'requires a redirect uri' do
151
+ subject.redirect_uri = nil
152
+ expect(subject).not_to be_authorizable
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec_helper_integration'
2
+
3
+ module Doorkeeper::OAuth
4
+ describe RefreshTokenRequest do
5
+ before do
6
+ allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
7
+ end
8
+ let(:server) do
9
+ double :server,
10
+ access_token_expires_in: 2.minutes,
11
+ custom_access_token_expires_in: -> (_oauth_client) { nil }
12
+ end
13
+ let(:refresh_token) do
14
+ FactoryGirl.create(:access_token, use_refresh_token: true)
15
+ end
16
+ let(:client) { refresh_token.application }
17
+ let(:credentials) { Client::Credentials.new(client.uid, client.secret) }
18
+
19
+ subject { RefreshTokenRequest.new server, refresh_token, credentials }
20
+
21
+ it 'issues a new token for the client' do
22
+ expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
23
+ expect(client.reload.access_tokens.last.expires_in).to eq(120)
24
+ end
25
+
26
+ it 'issues a new token for the client with custom expires_in' do
27
+ server = double :server,
28
+ access_token_expires_in: 2.minutes,
29
+ custom_access_token_expires_in: ->(_oauth_client) { 1234 }
30
+
31
+ allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
32
+
33
+ RefreshTokenRequest.new(server, refresh_token, credentials).authorize
34
+
35
+ expect(client.reload.access_tokens.last.expires_in).to eq(1234)
36
+ end
37
+
38
+ it 'revokes the previous token' do
39
+ expect { subject.authorize }.to change { refresh_token.revoked? }.from(false).to(true)
40
+ end
41
+
42
+ it 'requires the refresh token' do
43
+ subject.refresh_token = nil
44
+ subject.validate
45
+ expect(subject.error).to eq(:invalid_request)
46
+ end
47
+
48
+ it 'requires credentials to be valid if provided' do
49
+ subject.client = nil
50
+ subject.validate
51
+ expect(subject.error).to eq(:invalid_client)
52
+ end
53
+
54
+ it "requires the token's client and current client to match" do
55
+ subject.client = FactoryGirl.create(:application)
56
+ subject.validate
57
+ expect(subject.error).to eq(:invalid_grant)
58
+ end
59
+
60
+ it 'rejects revoked tokens' do
61
+ refresh_token.revoke
62
+ subject.validate
63
+ expect(subject.error).to eq(:invalid_grant)
64
+ end
65
+
66
+ it 'accepts expired tokens' do
67
+ refresh_token.expires_in = -1
68
+ refresh_token.save
69
+ subject.validate
70
+ expect(subject).to be_valid
71
+ end
72
+
73
+ context 'refresh tokens expire on access token use' do
74
+ let(:server) do
75
+ double :server,
76
+ access_token_expires_in: 2.minutes,
77
+ custom_access_token_expires_in: ->(_oauth_client) { 1234 }
78
+ end
79
+
80
+ before do
81
+ allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(true)
82
+ end
83
+
84
+ it 'issues a new token for the client' do
85
+ expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
86
+ end
87
+
88
+ it 'does not revoke the previous token' do
89
+ subject.authorize
90
+ expect(refresh_token).not_to be_revoked
91
+ end
92
+
93
+ it 'sets the previous refresh token in the new access token' do
94
+ subject.authorize
95
+ expect(
96
+ client.access_tokens.last.previous_refresh_token
97
+ ).to eq(refresh_token.refresh_token)
98
+ end
99
+ end
100
+
101
+ context 'clientless access tokens' do
102
+ let!(:refresh_token) { FactoryGirl.create(:clientless_access_token, use_refresh_token: true) }
103
+
104
+ subject { RefreshTokenRequest.new server, refresh_token, nil }
105
+
106
+ it 'issues a new token without a client' do
107
+ expect { subject.authorize }.to change { Doorkeeper::AccessToken.count }.by(1)
108
+ end
109
+ end
110
+
111
+ context 'with scopes' do
112
+ let(:refresh_token) do
113
+ FactoryGirl.create :access_token,
114
+ use_refresh_token: true,
115
+ scopes: 'public write'
116
+ end
117
+ let(:parameters) { {} }
118
+ subject { RefreshTokenRequest.new server, refresh_token, credentials, parameters }
119
+
120
+ it 'transfers scopes from the old token to the new token' do
121
+ subject.authorize
122
+ expect(Doorkeeper::AccessToken.last.scopes).to eq([:public, :write])
123
+ end
124
+
125
+ it 'reduces scopes to the provided scopes' do
126
+ parameters[:scopes] = 'public'
127
+ subject.authorize
128
+ expect(Doorkeeper::AccessToken.last.scopes).to eq([:public])
129
+ end
130
+
131
+ it 'validates that scopes are included in the original access token' do
132
+ parameters[:scopes] = 'public update'
133
+
134
+ subject.validate
135
+ expect(subject.error).to eq(:invalid_scope)
136
+ end
137
+
138
+ it 'uses params[:scope] in favor of scopes if present (valid)' do
139
+ parameters[:scopes] = 'public update'
140
+ parameters[:scope] = 'public'
141
+ subject.authorize
142
+ expect(Doorkeeper::AccessToken.last.scopes).to eq([:public])
143
+ end
144
+
145
+ it 'uses params[:scope] in favor of scopes if present (invalid)' do
146
+ parameters[:scopes] = 'public'
147
+ parameters[:scope] = 'public update'
148
+
149
+ subject.validate
150
+ expect(subject.error).to eq(:invalid_scope)
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,122 @@
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
+ expect(subject.all).to eq(['public'])
12
+ end
13
+
14
+ it 'allows you to add scopes with strings' do
15
+ subject.add 'public'
16
+ expect(subject.all).to eq(['public'])
17
+ end
18
+
19
+ it 'do not add already included scopes' do
20
+ subject.add :public
21
+ subject.add :public
22
+ expect(subject.all).to eq(['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
+ expect(subject.exists?('public')).to be_truthy
33
+ end
34
+
35
+ it 'returns false if scope with given name does not exist' do
36
+ expect(subject.exists?('other')).to be_falsey
37
+ end
38
+
39
+ it 'handles symbols' do
40
+ expect(subject.exists?(:public)).to be_truthy
41
+ expect(subject.exists?(:other)).to be_falsey
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 { expect(subject).to be_a(Scopes) }
51
+
52
+ describe '#all' do
53
+ it 'should be an array of the expected scopes' do
54
+ scopes_array = subject.all
55
+ expect(scopes_array.size).to eq(2)
56
+ expect(scopes_array).to include('public')
57
+ expect(scopes_array).to include('write')
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#+' do
63
+ it 'can add to another scope object' do
64
+ scopes = Scopes.from_string('public') + Scopes.from_string('admin')
65
+ expect(scopes.all).to eq(%w(public admin))
66
+ end
67
+
68
+ it 'does not change the existing object' do
69
+ origin = Scopes.from_string('public')
70
+ expect(origin.to_s).to eq('public')
71
+ end
72
+
73
+ it 'raises an error if cannot handle addition' do
74
+ expect do
75
+ Scopes.from_string('public') + 'admin'
76
+ end.to raise_error(NoMethodError)
77
+ end
78
+ end
79
+
80
+ describe '#==' do
81
+ it 'is equal to another set of scopes' do
82
+ expect(Scopes.from_string('public')).to eq(Scopes.from_string('public'))
83
+ end
84
+
85
+ it 'is equal to another set of scopes with no particular order' do
86
+ expect(Scopes.from_string('public write')).to eq(Scopes.from_string('write public'))
87
+ end
88
+
89
+ it 'differs from another set of scopes when scopes are not the same' do
90
+ expect(Scopes.from_string('public write')).not_to eq(Scopes.from_string('write'))
91
+ end
92
+ end
93
+
94
+ describe '#has_scopes?' do
95
+ subject { Scopes.from_string('public admin') }
96
+
97
+ it 'returns true when at least one scope is included' do
98
+ expect(subject.has_scopes?(Scopes.from_string('public'))).to be_truthy
99
+ end
100
+
101
+ it 'returns true when all scopes are included' do
102
+ expect(subject.has_scopes?(Scopes.from_string('public admin'))).to be_truthy
103
+ end
104
+
105
+ it 'is true if all scopes are included in any order' do
106
+ expect(subject.has_scopes?(Scopes.from_string('admin public'))).to be_truthy
107
+ end
108
+
109
+ it 'is false if no scopes are included' do
110
+ expect(subject.has_scopes?(Scopes.from_string('notexistent'))).to be_falsey
111
+ end
112
+
113
+ it 'returns false when any scope is not included' do
114
+ expect(subject.has_scopes?(Scopes.from_string('public nope'))).to be_falsey
115
+ end
116
+
117
+ it 'is false if no scopes are included even for existing ones' do
118
+ expect(subject.has_scopes?(Scopes.from_string('public admin notexistent'))).to be_falsey
119
+ end
120
+ end
121
+ end
122
+ end