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.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.gitignore +5 -0
- data/.travis.yml +16 -12
- data/Appraisals +14 -0
- data/CONTRIBUTING.md +2 -0
- data/Gemfile +5 -5
- data/NEWS.md +83 -2
- data/README.md +73 -43
- data/RELEASING.md +5 -12
- data/Rakefile +1 -1
- data/app/controllers/doorkeeper/application_controller.rb +3 -1
- data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
- data/app/controllers/doorkeeper/applications_controller.rb +3 -7
- data/app/controllers/doorkeeper/authorizations_controller.rb +1 -1
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +50 -14
- data/app/helpers/doorkeeper/dashboard_helper.rb +13 -11
- data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
- data/app/views/doorkeeper/applications/_form.html.erb +1 -1
- data/app/views/doorkeeper/applications/show.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
- data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
- data/app/views/layouts/doorkeeper/admin.html.erb +1 -1
- data/config/locales/en.yml +3 -2
- data/doorkeeper.gemspec +12 -10
- data/gemfiles/rails_4_2.gemfile +11 -0
- data/gemfiles/rails_5_0.gemfile +12 -0
- data/gemfiles/rails_5_1.gemfile +13 -0
- data/lib/doorkeeper/config.rb +73 -16
- data/lib/doorkeeper/engine.rb +11 -7
- data/lib/doorkeeper/errors.rb +18 -0
- data/lib/doorkeeper/grape/helpers.rb +2 -1
- data/lib/doorkeeper/helpers/controller.rb +8 -23
- data/lib/doorkeeper/models/access_grant_mixin.rb +21 -5
- data/lib/doorkeeper/models/access_token_mixin.rb +145 -23
- data/lib/doorkeeper/models/application_mixin.rb +21 -9
- data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +10 -2
- data/lib/doorkeeper/models/concerns/ownership.rb +6 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +37 -2
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
- data/lib/doorkeeper/oauth/authorization_code_request.rb +1 -4
- data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +3 -1
- data/lib/doorkeeper/oauth/base_response.rb +29 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +17 -6
- data/lib/doorkeeper/oauth/client.rb +0 -1
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -8
- data/lib/doorkeeper/oauth/code_response.rb +16 -16
- data/lib/doorkeeper/oauth/error_response.rb +9 -8
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +2 -1
- data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -13
- data/lib/doorkeeper/oauth/refresh_token_request.rb +22 -14
- data/lib/doorkeeper/oauth/scopes.rb +2 -2
- data/lib/doorkeeper/oauth/token.rb +20 -21
- data/lib/doorkeeper/oauth/token_request.rb +1 -2
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record/access_token.rb +25 -0
- data/lib/doorkeeper/orm/active_record/application.rb +12 -12
- data/lib/doorkeeper/orm/active_record.rb +0 -16
- data/lib/doorkeeper/rails/helpers.rb +1 -3
- data/lib/doorkeeper/rails/routes/mapper.rb +4 -4
- data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
- data/lib/doorkeeper/rails/routes.rb +4 -4
- data/lib/doorkeeper/request/authorization_code.rb +7 -1
- data/lib/doorkeeper/request/password.rb +11 -1
- data/lib/doorkeeper/request/refresh_token.rb +1 -1
- data/lib/doorkeeper/server.rb +0 -8
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/doorkeeper.rb +8 -2
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -0
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +1 -1
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb +11 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +8 -3
- data/lib/generators/doorkeeper/templates/migration.rb +23 -5
- data/spec/controllers/application_metal_controller.rb +10 -0
- data/spec/controllers/authorizations_controller_spec.rb +39 -24
- data/spec/controllers/protected_resources_controller_spec.rb +47 -18
- data/spec/controllers/tokens_controller_spec.rb +1 -1
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -4
- data/spec/dummy/app/controllers/home_controller.rb +1 -1
- data/spec/dummy/app/controllers/metal_controller.rb +1 -1
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +3 -3
- data/spec/dummy/app/models/user.rb +0 -4
- data/spec/dummy/config/application.rb +2 -36
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/test.rb +4 -15
- data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +6 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +2 -2
- data/spec/dummy/db/migrate/{20130902165751_create_doorkeeper_tables.rb → 20151223192035_create_doorkeeper_tables.rb} +24 -5
- data/spec/dummy/db/migrate/{20130902175349_add_owner_to_application.rb → 20151223200000_add_owner_to_application.rb} +0 -0
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +11 -0
- data/spec/dummy/db/schema.rb +23 -22
- data/spec/factories.rb +3 -1
- data/spec/lib/config_spec.rb +19 -2
- data/spec/lib/doorkeeper_spec.rb +135 -13
- data/spec/lib/models/expirable_spec.rb +0 -1
- data/spec/lib/models/revocable_spec.rb +27 -4
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +1 -2
- data/spec/lib/oauth/authorization_code_request_spec.rb +1 -1
- data/spec/lib/oauth/base_request_spec.rb +160 -0
- data/spec/lib/oauth/base_response_spec.rb +45 -0
- data/spec/lib/oauth/client/credentials_spec.rb +41 -0
- data/spec/lib/oauth/code_response_spec.rb +34 -0
- data/spec/lib/oauth/error_response_spec.rb +9 -9
- data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
- data/spec/lib/oauth/password_access_token_request_spec.rb +5 -5
- data/spec/lib/oauth/refresh_token_request_spec.rb +34 -3
- data/spec/lib/oauth/scopes_spec.rb +0 -1
- data/spec/lib/oauth/token_spec.rb +12 -5
- data/spec/lib/server_spec.rb +0 -3
- data/spec/models/doorkeeper/access_token_spec.rb +45 -1
- data/spec/models/doorkeeper/application_spec.rb +3 -11
- data/spec/requests/endpoints/authorization_spec.rb +5 -6
- data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
- data/spec/requests/flows/authorization_code_spec.rb +4 -12
- data/spec/requests/flows/password_spec.rb +26 -5
- data/spec/requests/flows/refresh_token_spec.rb +87 -17
- data/spec/requests/flows/revoke_token_spec.rb +100 -86
- data/spec/spec_helper.rb +2 -0
- data/spec/spec_helper_integration.rb +8 -1
- data/spec/support/helpers/model_helper.rb +27 -5
- data/spec/support/helpers/request_spec_helper.rb +12 -4
- data/spec/support/http_method_shim.rb +38 -0
- data/spec/support/shared/controllers_shared_context.rb +13 -4
- data/spec/support/shared/models_shared_examples.rb +1 -1
- metadata +72 -42
- data/lib/doorkeeper/oauth/client/methods.rb +0 -18
- data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
- data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
- data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
- 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
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
#
|
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(
|
134
|
-
|
135
|
-
|
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: :
|
11
|
-
has_many :access_tokens, dependent: :
|
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
|
-
|
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
|
-
|
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.
|
50
|
+
Doorkeeper::Application.column_names.include?("scopes")
|
39
51
|
end
|
40
52
|
|
41
53
|
def generate_uid
|
@@ -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
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
17
|
-
uri = URI.parse(url)
|
18
|
-
uri.fragment = build_query(parameters)
|
19
|
-
uri.to_s
|
20
|
-
end
|
21
|
+
private
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
@@ -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
|
-
|
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
|
@@ -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
|
10
|
+
@server = server
|
11
|
+
@validation = validation
|
11
12
|
end
|
12
13
|
|
13
14
|
def create(client, scopes, creator = Creator.new)
|
@@ -4,13 +4,12 @@ require 'doorkeeper/oauth/client_credentials/validation'
|
|
4
4
|
|
5
5
|
module Doorkeeper
|
6
6
|
module OAuth
|
7
|
-
class ClientCredentialsRequest
|
8
|
-
|
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
|
-
|
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
|
23
|
-
@
|
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
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|