doorkeeper 3.1.0 → 4.2.6

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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +5 -0
  4. data/.travis.yml +16 -12
  5. data/Appraisals +14 -0
  6. data/CONTRIBUTING.md +2 -0
  7. data/Gemfile +5 -5
  8. data/NEWS.md +83 -2
  9. data/README.md +73 -43
  10. data/RELEASING.md +5 -12
  11. data/Rakefile +1 -1
  12. data/app/controllers/doorkeeper/application_controller.rb +3 -1
  13. data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
  14. data/app/controllers/doorkeeper/applications_controller.rb +3 -7
  15. data/app/controllers/doorkeeper/authorizations_controller.rb +1 -1
  16. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  17. data/app/controllers/doorkeeper/tokens_controller.rb +50 -14
  18. data/app/helpers/doorkeeper/dashboard_helper.rb +13 -11
  19. data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
  20. data/app/views/doorkeeper/applications/_form.html.erb +1 -1
  21. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  22. data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
  23. data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
  24. data/app/views/layouts/doorkeeper/admin.html.erb +1 -1
  25. data/config/locales/en.yml +3 -2
  26. data/doorkeeper.gemspec +12 -10
  27. data/gemfiles/rails_4_2.gemfile +11 -0
  28. data/gemfiles/rails_5_0.gemfile +12 -0
  29. data/gemfiles/rails_5_1.gemfile +13 -0
  30. data/lib/doorkeeper/config.rb +73 -16
  31. data/lib/doorkeeper/engine.rb +11 -7
  32. data/lib/doorkeeper/errors.rb +18 -0
  33. data/lib/doorkeeper/grape/helpers.rb +2 -1
  34. data/lib/doorkeeper/helpers/controller.rb +8 -23
  35. data/lib/doorkeeper/models/access_grant_mixin.rb +21 -5
  36. data/lib/doorkeeper/models/access_token_mixin.rb +145 -23
  37. data/lib/doorkeeper/models/application_mixin.rb +21 -9
  38. data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
  39. data/lib/doorkeeper/models/concerns/expirable.rb +10 -2
  40. data/lib/doorkeeper/models/concerns/ownership.rb +6 -1
  41. data/lib/doorkeeper/models/concerns/revocable.rb +37 -2
  42. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
  43. data/lib/doorkeeper/oauth/authorization_code_request.rb +1 -4
  44. data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +3 -1
  45. data/lib/doorkeeper/oauth/base_response.rb +29 -0
  46. data/lib/doorkeeper/oauth/client/credentials.rb +17 -6
  47. data/lib/doorkeeper/oauth/client.rb +0 -1
  48. data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
  49. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
  50. data/lib/doorkeeper/oauth/client_credentials/validation.rb +1 -1
  51. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -8
  52. data/lib/doorkeeper/oauth/code_response.rb +16 -16
  53. data/lib/doorkeeper/oauth/error_response.rb +9 -8
  54. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
  55. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +2 -1
  56. data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -0
  57. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -13
  58. data/lib/doorkeeper/oauth/refresh_token_request.rb +22 -14
  59. data/lib/doorkeeper/oauth/scopes.rb +2 -2
  60. data/lib/doorkeeper/oauth/token.rb +20 -21
  61. data/lib/doorkeeper/oauth/token_request.rb +1 -2
  62. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  63. data/lib/doorkeeper/orm/active_record/access_token.rb +25 -0
  64. data/lib/doorkeeper/orm/active_record/application.rb +12 -12
  65. data/lib/doorkeeper/orm/active_record.rb +0 -16
  66. data/lib/doorkeeper/rails/helpers.rb +1 -3
  67. data/lib/doorkeeper/rails/routes/mapper.rb +4 -4
  68. data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
  69. data/lib/doorkeeper/rails/routes.rb +4 -4
  70. data/lib/doorkeeper/request/authorization_code.rb +7 -1
  71. data/lib/doorkeeper/request/password.rb +11 -1
  72. data/lib/doorkeeper/request/refresh_token.rb +1 -1
  73. data/lib/doorkeeper/server.rb +0 -8
  74. data/lib/doorkeeper/version.rb +1 -1
  75. data/lib/doorkeeper.rb +8 -2
  76. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -0
  77. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +1 -1
  78. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb +11 -0
  79. data/lib/generators/doorkeeper/templates/initializer.rb +8 -3
  80. data/lib/generators/doorkeeper/templates/migration.rb +23 -5
  81. data/spec/controllers/application_metal_controller.rb +10 -0
  82. data/spec/controllers/authorizations_controller_spec.rb +39 -24
  83. data/spec/controllers/protected_resources_controller_spec.rb +47 -18
  84. data/spec/controllers/tokens_controller_spec.rb +1 -1
  85. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -4
  86. data/spec/dummy/app/controllers/home_controller.rb +1 -1
  87. data/spec/dummy/app/controllers/metal_controller.rb +1 -1
  88. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +3 -3
  89. data/spec/dummy/app/models/user.rb +0 -4
  90. data/spec/dummy/config/application.rb +2 -36
  91. data/spec/dummy/config/environment.rb +1 -1
  92. data/spec/dummy/config/environments/test.rb +4 -15
  93. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +6 -0
  94. data/spec/dummy/config/initializers/doorkeeper.rb +2 -2
  95. data/spec/dummy/db/migrate/{20130902165751_create_doorkeeper_tables.rb → 20151223192035_create_doorkeeper_tables.rb} +24 -5
  96. data/spec/dummy/db/migrate/{20130902175349_add_owner_to_application.rb → 20151223200000_add_owner_to_application.rb} +0 -0
  97. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +11 -0
  98. data/spec/dummy/db/schema.rb +23 -22
  99. data/spec/factories.rb +3 -1
  100. data/spec/lib/config_spec.rb +19 -2
  101. data/spec/lib/doorkeeper_spec.rb +135 -13
  102. data/spec/lib/models/expirable_spec.rb +0 -1
  103. data/spec/lib/models/revocable_spec.rb +27 -4
  104. data/spec/lib/oauth/authorization/uri_builder_spec.rb +1 -2
  105. data/spec/lib/oauth/authorization_code_request_spec.rb +1 -1
  106. data/spec/lib/oauth/base_request_spec.rb +160 -0
  107. data/spec/lib/oauth/base_response_spec.rb +45 -0
  108. data/spec/lib/oauth/client/credentials_spec.rb +41 -0
  109. data/spec/lib/oauth/code_response_spec.rb +34 -0
  110. data/spec/lib/oauth/error_response_spec.rb +9 -9
  111. data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
  112. data/spec/lib/oauth/password_access_token_request_spec.rb +5 -5
  113. data/spec/lib/oauth/refresh_token_request_spec.rb +34 -3
  114. data/spec/lib/oauth/scopes_spec.rb +0 -1
  115. data/spec/lib/oauth/token_spec.rb +12 -5
  116. data/spec/lib/server_spec.rb +0 -3
  117. data/spec/models/doorkeeper/access_token_spec.rb +45 -1
  118. data/spec/models/doorkeeper/application_spec.rb +3 -11
  119. data/spec/requests/endpoints/authorization_spec.rb +5 -6
  120. data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
  121. data/spec/requests/flows/authorization_code_spec.rb +4 -12
  122. data/spec/requests/flows/password_spec.rb +26 -5
  123. data/spec/requests/flows/refresh_token_spec.rb +87 -17
  124. data/spec/requests/flows/revoke_token_spec.rb +100 -86
  125. data/spec/spec_helper.rb +2 -0
  126. data/spec/spec_helper_integration.rb +8 -1
  127. data/spec/support/helpers/model_helper.rb +27 -5
  128. data/spec/support/helpers/request_spec_helper.rb +12 -4
  129. data/spec/support/http_method_shim.rb +38 -0
  130. data/spec/support/shared/controllers_shared_context.rb +13 -4
  131. data/spec/support/shared/models_shared_examples.rb +1 -1
  132. metadata +72 -42
  133. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  134. data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
  135. data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
  136. data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
  137. data/spec/lib/oauth/client/methods_spec.rb +0 -54
@@ -10,20 +10,23 @@ module Doorkeeper
10
10
  include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
11
11
 
12
12
  included do
13
- belongs_to :application,
14
- class_name: 'Doorkeeper::Application',
15
- inverse_of: :access_tokens
13
+ belongs_to_options = {
14
+ class_name: 'Doorkeeper::Application',
15
+ inverse_of: :access_tokens
16
+ }
17
+ if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
18
+ belongs_to_options[:optional] = true
19
+ end
20
+
21
+ belongs_to :application, belongs_to_options
16
22
 
17
23
  validates :token, presence: true, uniqueness: true
18
24
  validates :refresh_token, uniqueness: true, if: :use_refresh_token?
19
25
 
26
+ # @attr_writer [Boolean, nil] use_refresh_token
27
+ # indicates the possibility of using refresh token
20
28
  attr_writer :use_refresh_token
21
29
 
22
- if respond_to?(:attr_accessible)
23
- attr_accessible :application_id, :resource_owner_id, :expires_in,
24
- :scopes, :use_refresh_token
25
- end
26
-
27
30
  before_validation :generate_token, on: :create
28
31
  before_validation :generate_refresh_token,
29
32
  on: :create,
@@ -31,21 +34,60 @@ module Doorkeeper
31
34
  end
32
35
 
33
36
  module ClassMethods
37
+ # Returns an instance of the Doorkeeper::AccessToken with
38
+ # specific token value.
39
+ #
40
+ # @param token [#to_s]
41
+ # token value (any object that responds to `#to_s`)
42
+ #
43
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
44
+ # if there is no record with such token
45
+ #
34
46
  def by_token(token)
35
- where(token: token.to_s).limit(1).to_a.first
47
+ find_by(token: token.to_s)
36
48
  end
37
49
 
50
+ # Returns an instance of the Doorkeeper::AccessToken
51
+ # with specific token value.
52
+ #
53
+ # @param refresh_token [#to_s]
54
+ # refresh token value (any object that responds to `#to_s`)
55
+ #
56
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
57
+ # if there is no record with such refresh token
58
+ #
38
59
  def by_refresh_token(refresh_token)
39
- where(refresh_token: refresh_token.to_s).first
60
+ find_by(refresh_token: refresh_token.to_s)
40
61
  end
41
62
 
63
+ # Revokes AccessToken records that have not been revoked and associated
64
+ # with the specific Application and Resource Owner.
65
+ #
66
+ # @param application_id [Integer]
67
+ # ID of the Application
68
+ # @param resource_owner [ActiveRecord::Base]
69
+ # instance of the Resource Owner model
70
+ #
42
71
  def revoke_all_for(application_id, resource_owner)
43
72
  where(application_id: application_id,
44
73
  resource_owner_id: resource_owner.id,
45
74
  revoked_at: nil).
46
- map(&:revoke)
75
+ each(&:revoke)
47
76
  end
48
77
 
78
+ # Looking for not expired Access Token with a matching set of scopes
79
+ # that belongs to specific Application and Resource Owner.
80
+ #
81
+ # @param application [Doorkeeper::Application]
82
+ # Application instance
83
+ # @param resource_owner_or_id [ActiveRecord::Base, Integer]
84
+ # Resource Owner model instance or it's ID
85
+ # @param scopes [String, Doorkeeper::OAuth::Scopes]
86
+ # set of scopes
87
+ #
88
+ # @return [Doorkeeper::AccessToken, nil] Access Token instance or
89
+ # nil if matching record was not found
90
+ #
49
91
  def matching_token_for(application, resource_owner_or_id, scopes)
50
92
  resource_owner_id = if resource_owner_or_id.respond_to?(:to_key)
51
93
  resource_owner_or_id.id
@@ -58,6 +100,19 @@ module Doorkeeper
58
100
  end
59
101
  end
60
102
 
103
+ # Checks whether the token scopes match the scopes from the parameters or
104
+ # Application scopes (if present).
105
+ #
106
+ # @param token_scopes [#to_s]
107
+ # set of scopes (any object that responds to `#to_s`)
108
+ # @param param_scopes [String]
109
+ # scopes from params
110
+ # @param app_scopes [String]
111
+ # Application scopes
112
+ #
113
+ # @return [Boolean] true if all scopes and blank or matches
114
+ # and false in other cases
115
+ #
61
116
  def scopes_match?(token_scopes, param_scopes, app_scopes)
62
117
  (!token_scopes.present? && !param_scopes.present?) ||
63
118
  Doorkeeper::OAuth::Helpers::ScopeChecker.match?(
@@ -67,6 +122,23 @@ module Doorkeeper
67
122
  )
68
123
  end
69
124
 
125
+ # Looking for not expired AccessToken record with a matching set of
126
+ # scopes that belongs to specific Application and Resource Owner.
127
+ # If it doesn't exists - then creates it.
128
+ #
129
+ # @param application [Doorkeeper::Application]
130
+ # Application instance
131
+ # @param resource_owner_id [ActiveRecord::Base, Integer]
132
+ # Resource Owner model instance or it's ID
133
+ # @param scopes [#to_s]
134
+ # set of scopes (any object that responds to `#to_s`)
135
+ # @param expires_in [Integer]
136
+ # token lifetime in seconds
137
+ # @param use_refresh_token [Boolean]
138
+ # whether to use the refresh token
139
+ #
140
+ # @return [Doorkeeper::AccessToken] existing record or a new one
141
+ #
70
142
  def find_or_create_for(application, resource_owner_id, scopes, expires_in, use_refresh_token)
71
143
  if Doorkeeper.configuration.reuse_access_token
72
144
  access_token = matching_token_for(application, resource_owner_id, scopes)
@@ -74,6 +146,7 @@ module Doorkeeper
74
146
  return access_token
75
147
  end
76
148
  end
149
+
77
150
  create!(
78
151
  application_id: application.try(:id),
79
152
  resource_owner_id: resource_owner_id,
@@ -83,56 +156,105 @@ module Doorkeeper
83
156
  )
84
157
  end
85
158
 
159
+ # Looking for not revoked Access Token record that belongs to specific
160
+ # Application and Resource Owner.
161
+ #
162
+ # @param application_id [Integer]
163
+ # ID of the Application model instance
164
+ # @param resource_owner_id [Integer]
165
+ # ID of the Resource Owner model instance
166
+ #
167
+ # @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
168
+ # nil if nothing was found
169
+ #
86
170
  def last_authorized_token_for(application_id, resource_owner_id)
87
- where(application_id: application_id,
88
- resource_owner_id: resource_owner_id,
89
- revoked_at: nil).
90
- send(order_method, created_at_desc).
91
- limit(1).
92
- to_a.
93
- first
171
+ send(order_method, created_at_desc).
172
+ find_by(application_id: application_id,
173
+ resource_owner_id: resource_owner_id,
174
+ revoked_at: nil)
94
175
  end
95
176
  end
96
177
 
178
+ # Access Token type: Bearer.
179
+ # @see https://tools.ietf.org/html/rfc6750
180
+ # The OAuth 2.0 Authorization Framework: Bearer Token Usage
181
+ #
97
182
  def token_type
98
183
  'bearer'
99
184
  end
100
185
 
101
186
  def use_refresh_token?
187
+ @use_refresh_token ||= false
102
188
  !!@use_refresh_token
103
189
  end
104
190
 
191
+ # JSON representation of the Access Token instance.
192
+ #
193
+ # @return [Hash] hash with token data
105
194
  def as_json(_options = {})
106
195
  {
107
196
  resource_owner_id: resource_owner_id,
108
197
  scopes: scopes,
109
198
  expires_in_seconds: expires_in_seconds,
110
199
  application: { uid: application.try(:uid) },
111
- created_at: created_at.to_i,
200
+ created_at: created_at.to_i
112
201
  }
113
202
  end
114
203
 
115
- # It indicates whether the tokens have the same credential
204
+ # Indicates whether the token instance have the same credential
205
+ # as the other Access Token.
206
+ #
207
+ # @param access_token [Doorkeeper::AccessToken] other token
208
+ #
209
+ # @return [Boolean] true if credentials are same of false in other cases
210
+ #
116
211
  def same_credential?(access_token)
117
212
  application_id == access_token.application_id &&
118
213
  resource_owner_id == access_token.resource_owner_id
119
214
  end
120
215
 
216
+ # Indicates if token is acceptable for specific scopes.
217
+ #
218
+ # @param scopes [Array<String>] scopes
219
+ #
220
+ # @return [Boolean] true if record is accessible and includes scopes or
221
+ # false in other cases
222
+ #
121
223
  def acceptable?(scopes)
122
224
  accessible? && includes_scope?(*scopes)
123
225
  end
124
226
 
125
227
  private
126
228
 
229
+ # Generates refresh token with UniqueToken generator.
230
+ #
231
+ # @return [String] refresh token value
232
+ #
127
233
  def generate_refresh_token
128
234
  write_attribute :refresh_token, UniqueToken.generate
129
235
  end
130
236
 
237
+ # Generates and sets the token value with the
238
+ # configured Generator class (see Doorkeeper.configuration).
239
+ #
240
+ # @return [String] generated token value
241
+ #
242
+ # @raise [Doorkeeper::Errors::UnableToGenerateToken]
243
+ # custom class doesn't implement .generate method
244
+ # @raise [Doorkeeper::Errors::TokenGeneratorNotFound]
245
+ # custom class doesn't exist
246
+ #
131
247
  def generate_token
248
+ self.created_at ||= Time.now.utc
249
+
132
250
  generator = Doorkeeper.configuration.access_token_generator.constantize
133
- self.token = generator.generate(resource_owner_id: resource_owner_id,
134
- scopes: scopes, application: application,
135
- expires_in: expires_in)
251
+ self.token = generator.generate(
252
+ resource_owner_id: resource_owner_id,
253
+ scopes: scopes,
254
+ application: application,
255
+ expires_in: expires_in,
256
+ created_at: created_at
257
+ )
136
258
  rescue NoMethodError
137
259
  raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
138
260
  rescue NameError
@@ -7,27 +7,39 @@ module Doorkeeper
7
7
  include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
8
8
 
9
9
  included do
10
- has_many :access_grants, dependent: :destroy, class_name: 'Doorkeeper::AccessGrant'
11
- has_many :access_tokens, dependent: :destroy, class_name: 'Doorkeeper::AccessToken'
10
+ has_many :access_grants, dependent: :delete_all, class_name: 'Doorkeeper::AccessGrant'
11
+ has_many :access_tokens, dependent: :delete_all, class_name: 'Doorkeeper::AccessToken'
12
12
 
13
13
  validates :name, :secret, :uid, presence: true
14
14
  validates :uid, uniqueness: true
15
15
  validates :redirect_uri, redirect_uri: true
16
16
 
17
17
  before_validation :generate_uid, :generate_secret, on: :create
18
-
19
- if respond_to?(:attr_accessible)
20
- attr_accessible :name, :redirect_uri, :scopes
21
- end
22
18
  end
23
19
 
24
20
  module ClassMethods
21
+ # Returns an instance of the Doorkeeper::Application with
22
+ # specific UID and secret.
23
+ #
24
+ # @param uid [#to_s] UID (any object that responds to `#to_s`)
25
+ # @param secret [#to_s] secret (any object that responds to `#to_s`)
26
+ #
27
+ # @return [Doorkeeper::Application, nil] Application instance or nil
28
+ # if there is no record with such credentials
29
+ #
25
30
  def by_uid_and_secret(uid, secret)
26
- where(uid: uid.to_s, secret: secret.to_s).limit(1).to_a.first
31
+ find_by(uid: uid.to_s, secret: secret.to_s)
27
32
  end
28
33
 
34
+ # Returns an instance of the Doorkeeper::Application with specific UID.
35
+ #
36
+ # @param uid [#to_s] UID (any object that responds to `#to_s`)
37
+ #
38
+ # @return [Doorkeeper::Application, nil] Application instance or nil
39
+ # if there is no record with such UID
40
+ #
29
41
  def by_uid(uid)
30
- where(uid: uid.to_s).limit(1).to_a.first
42
+ find_by(uid: uid.to_s)
31
43
  end
32
44
  end
33
45
 
@@ -35,7 +47,7 @@ module Doorkeeper
35
47
 
36
48
  def has_scopes?
37
49
  Doorkeeper.configuration.orm != :active_record ||
38
- Application.new.attributes.include?("scopes")
50
+ Doorkeeper::Application.column_names.include?("scopes")
39
51
  end
40
52
 
41
53
  def generate_uid
@@ -1,6 +1,10 @@
1
1
  module Doorkeeper
2
2
  module Models
3
3
  module Accessible
4
+ # Indicates whether the object is accessible (not expired and not revoked).
5
+ #
6
+ # @return [Boolean] true if object accessible or false in other case
7
+ #
4
8
  def accessible?
5
9
  !expired? && !revoked?
6
10
  end
@@ -1,13 +1,21 @@
1
1
  module Doorkeeper
2
2
  module Models
3
3
  module Expirable
4
+ # Indicates whether the object is expired (`#expires_in` present and
5
+ # expiration time has come).
6
+ #
7
+ # @return [Boolean] true if object expired and false in other case
4
8
  def expired?
5
- expires_in && Time.now > expired_time
9
+ expires_in && Time.now.utc > expired_time
6
10
  end
7
11
 
12
+ # Calculates expiration time in seconds.
13
+ #
14
+ # @return [Integer, nil] number of seconds if object has expiration time
15
+ # or nil if object never expires.
8
16
  def expires_in_seconds
9
17
  return nil if expires_in.nil?
10
- expires = (created_at + expires_in.seconds) - Time.now
18
+ expires = (created_at + expires_in.seconds) - Time.now.utc
11
19
  expires_sec = expires.seconds.round(0)
12
20
  expires_sec > 0 ? expires_sec : 0
13
21
  end
@@ -4,7 +4,12 @@ module Doorkeeper
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- belongs_to :owner, polymorphic: true
7
+ belongs_to_options = { polymorphic: true }
8
+ if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
9
+ belongs_to_options[:optional] = true
10
+ end
11
+
12
+ belongs_to :owner, belongs_to_options
8
13
  validates :owner, presence: true, if: :validate_owner?
9
14
  end
10
15
 
@@ -1,12 +1,47 @@
1
1
  module Doorkeeper
2
2
  module Models
3
3
  module Revocable
4
+ # Revokes the object (updates `:revoked_at` attribute setting its value
5
+ # to the specific time).
6
+ #
7
+ # @param clock [Time] time object
8
+ #
4
9
  def revoke(clock = Time)
5
- update_attribute :revoked_at, clock.now
10
+ update_attribute :revoked_at, clock.now.utc
6
11
  end
7
12
 
13
+ # Indicates whether the object has been revoked.
14
+ #
15
+ # @return [Boolean] true if revoked, false in other case
16
+ #
8
17
  def revoked?
9
- !!(revoked_at && revoked_at <= Time.now)
18
+ !!(revoked_at && revoked_at <= Time.now.utc)
19
+ end
20
+
21
+ # Revokes token with `:refresh_token` equal to `:previous_refresh_token`
22
+ # and clears `:previous_refresh_token` attribute.
23
+ #
24
+ def revoke_previous_refresh_token!
25
+ return unless refresh_token_revoked_on_use?
26
+ old_refresh_token.revoke if old_refresh_token
27
+ update_attribute :previous_refresh_token, ""
28
+ end
29
+
30
+ private
31
+
32
+ # Searches for Access Token record with `:refresh_token` equal to
33
+ # `:previous_refresh_token` value.
34
+ #
35
+ # @return [Doorkeeper::AccessToken, nil]
36
+ # Access Token record or nil if nothing found
37
+ #
38
+ def old_refresh_token
39
+ @old_refresh_token ||=
40
+ AccessToken.by_refresh_token(previous_refresh_token)
41
+ end
42
+
43
+ def refresh_token_revoked_on_use?
44
+ AccessToken.refresh_token_revoked_on_use?
10
45
  end
11
46
  end
12
47
  end
@@ -1,27 +1,29 @@
1
+ require 'rack/utils'
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Authorization
4
- module URIBuilder
5
- include Rack::Utils
6
-
7
- extend self
6
+ class URIBuilder
7
+ class << self
8
+ def uri_with_query(url, parameters = {})
9
+ uri = URI.parse(url)
10
+ original_query = Rack::Utils.parse_query(uri.query)
11
+ uri.query = build_query(original_query.merge(parameters))
12
+ uri.to_s
13
+ end
8
14
 
9
- def uri_with_query(url, parameters = {})
10
- uri = URI.parse(url)
11
- original_query = parse_query(uri.query)
12
- uri.query = build_query(original_query.merge(parameters))
13
- uri.to_s
14
- end
15
+ def uri_with_fragment(url, parameters = {})
16
+ uri = URI.parse(url)
17
+ uri.fragment = build_query(parameters)
18
+ uri.to_s
19
+ end
15
20
 
16
- def uri_with_fragment(url, parameters = {})
17
- uri = URI.parse(url)
18
- uri.fragment = build_query(parameters)
19
- uri.to_s
20
- end
21
+ private
21
22
 
22
- def build_query(parameters = {})
23
- parameters = parameters.reject { |k, v| v.blank? }
24
- super parameters
23
+ def build_query(parameters = {})
24
+ parameters = parameters.reject { |_, v| v.blank? }
25
+ Rack::Utils.build_query parameters
26
+ end
25
27
  end
26
28
  end
27
29
  end
@@ -1,9 +1,6 @@
1
1
  module Doorkeeper
2
2
  module OAuth
3
- class AuthorizationCodeRequest
4
- include Validations
5
- include OAuth::RequestConcern
6
-
3
+ class AuthorizationCodeRequest < BaseRequest
7
4
  validate :attributes, error: :invalid_request
8
5
  validate :client, error: :invalid_client
9
6
  validate :grant, error: :invalid_grant
@@ -1,6 +1,8 @@
1
1
  module Doorkeeper
2
2
  module OAuth
3
- module RequestConcern
3
+ class BaseRequest
4
+ include Validations
5
+
4
6
  def authorize
5
7
  validate
6
8
  if valid?
@@ -0,0 +1,29 @@
1
+ module Doorkeeper
2
+ module OAuth
3
+ class BaseResponse
4
+ def body
5
+ {}
6
+ end
7
+
8
+ def description
9
+ ""
10
+ end
11
+
12
+ def headers
13
+ {}
14
+ end
15
+
16
+ def redirectable?
17
+ false
18
+ end
19
+
20
+ def redirect_uri
21
+ ""
22
+ end
23
+
24
+ def status
25
+ :ok
26
+ end
27
+ end
28
+ end
29
+ end
@@ -2,13 +2,24 @@ module Doorkeeper
2
2
  module OAuth
3
3
  class Client
4
4
  class Credentials < Struct.new(:uid, :secret)
5
- extend Methods
5
+ class << self
6
+ def from_request(request, *credentials_methods)
7
+ credentials_methods.inject(nil) do |credentials, method|
8
+ method = self.method(method) if method.is_a?(Symbol)
9
+ credentials = Credentials.new(*method.call(request))
10
+ break credentials unless credentials.blank?
11
+ end
12
+ end
13
+
14
+ def from_params(request)
15
+ request.parameters.values_at(:client_id, :client_secret)
16
+ end
6
17
 
7
- def self.from_request(request, *credentials_methods)
8
- credentials_methods.inject(nil) do |credentials, method|
9
- method = self.method(method) if method.is_a?(Symbol)
10
- credentials = Credentials.new *method.call(request)
11
- break credentials unless credentials.blank?
18
+ def from_basic(request)
19
+ authorization = request.authorization
20
+ if authorization.present? && authorization =~ /^Basic (.*)/m
21
+ Base64.decode64($1).split(/:/, 2)
22
+ end
12
23
  end
13
24
  end
14
25
 
@@ -1,4 +1,3 @@
1
- require 'doorkeeper/oauth/client/methods'
2
1
  require 'doorkeeper/oauth/client/credentials'
3
2
 
4
3
  module Doorkeeper
@@ -1,6 +1,6 @@
1
1
  module Doorkeeper
2
2
  module OAuth
3
- class ClientCredentialsRequest
3
+ class ClientCredentialsRequest < BaseRequest
4
4
  class Creator
5
5
  def call(client, scopes, attributes = {})
6
6
  AccessToken.find_or_create_for(
@@ -2,12 +2,13 @@ require 'doorkeeper/oauth/client_credentials/validation'
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
- class ClientCredentialsRequest
5
+ class ClientCredentialsRequest < BaseRequest
6
6
  class Issuer
7
7
  attr_accessor :token, :validation, :error
8
8
 
9
9
  def initialize(server, validation)
10
- @server, @validation = server, validation
10
+ @server = server
11
+ @validation = validation
11
12
  end
12
13
 
13
14
  def create(client, scopes, creator = Creator.new)
@@ -4,7 +4,7 @@ require 'doorkeeper/oauth/helpers/scope_checker'
4
4
 
5
5
  module Doorkeeper
6
6
  module OAuth
7
- class ClientCredentialsRequest
7
+ class ClientCredentialsRequest < BaseRequest
8
8
  class Validation
9
9
  include Validations
10
10
  include OAuth::Helpers
@@ -4,13 +4,12 @@ require 'doorkeeper/oauth/client_credentials/validation'
4
4
 
5
5
  module Doorkeeper
6
6
  module OAuth
7
- class ClientCredentialsRequest
8
- include Validations
9
- include OAuth::RequestConcern
10
-
11
- attr_accessor :issuer, :server, :client, :original_scopes
7
+ class ClientCredentialsRequest < BaseRequest
8
+ attr_accessor :server, :client, :original_scopes
12
9
  attr_reader :response
13
- alias :error_response :response
10
+ attr_writer :issuer
11
+
12
+ alias_method :error_response, :response
14
13
 
15
14
  delegate :error, to: :issuer
16
15
 
@@ -19,8 +18,9 @@ module Doorkeeper
19
18
  end
20
19
 
21
20
  def initialize(server, client, parameters = {})
22
- @client, @server = client, server
23
- @response = nil
21
+ @client = client
22
+ @server = server
23
+ @response = nil
24
24
  @original_scopes = parameters[:scope]
25
25
  end
26
26
 
@@ -1,13 +1,13 @@
1
1
  module Doorkeeper
2
2
  module OAuth
3
- class CodeResponse
4
- include OAuth::Authorization::URIBuilder
3
+ class CodeResponse < BaseResponse
5
4
  include OAuth::Helpers
6
5
 
7
6
  attr_accessor :pre_auth, :auth, :response_on_fragment
8
7
 
9
8
  def initialize(pre_auth, auth, options = {})
10
- @pre_auth, @auth = pre_auth, auth
9
+ @pre_auth = pre_auth
10
+ @auth = auth
11
11
  @response_on_fragment = options[:response_on_fragment]
12
12
  end
13
13
 
@@ -18,20 +18,20 @@ module Doorkeeper
18
18
  def redirect_uri
19
19
  if URIChecker.native_uri? pre_auth.redirect_uri
20
20
  auth.native_redirect
21
+ elsif response_on_fragment
22
+ Authorization::URIBuilder.uri_with_fragment(
23
+ pre_auth.redirect_uri,
24
+ access_token: auth.token.token,
25
+ token_type: auth.token.token_type,
26
+ expires_in: auth.token.expires_in_seconds,
27
+ state: pre_auth.state
28
+ )
21
29
  else
22
- if response_on_fragment
23
- uri_with_fragment(
24
- pre_auth.redirect_uri,
25
- access_token: auth.token.token,
26
- token_type: auth.token.token_type,
27
- expires_in: auth.token.expires_in,
28
- state: pre_auth.state
29
- )
30
- else
31
- uri_with_query pre_auth.redirect_uri,
32
- code: auth.token.token,
33
- state: pre_auth.state
34
- end
30
+ Authorization::URIBuilder.uri_with_query(
31
+ pre_auth.redirect_uri,
32
+ code: auth.token.token,
33
+ state: pre_auth.state
34
+ )
35
35
  end
36
36
  end
37
37
  end