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.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.github/ISSUE_TEMPLATE.md +25 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
- data/.gitignore +6 -1
- data/.hound.yml +2 -13
- data/.rubocop.yml +17 -0
- data/.travis.yml +26 -10
- data/Appraisals +18 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/CONTRIBUTING.md +2 -0
- data/Gemfile +5 -5
- data/NEWS.md +141 -2
- data/README.md +149 -66
- data/RELEASING.md +5 -12
- data/Rakefile +1 -1
- data/SECURITY.md +15 -0
- data/app/controllers/doorkeeper/application_controller.rb +4 -6
- data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
- data/app/controllers/doorkeeper/applications_controller.rb +18 -8
- 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 +62 -15
- data/app/helpers/doorkeeper/dashboard_helper.rb +14 -10
- data/app/validators/redirect_uri_validator.rb +12 -2
- data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
- data/app/views/doorkeeper/applications/_form.html.erb +13 -2
- data/app/views/doorkeeper/applications/index.html.erb +2 -0
- data/app/views/doorkeeper/applications/show.html.erb +4 -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/doorkeeper/authorized_applications/index.html.erb +0 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +1 -1
- data/config/locales/en.yml +12 -7
- data/doorkeeper.gemspec +16 -11
- data/gemfiles/rails_4_2.gemfile +13 -0
- data/gemfiles/rails_5_0.gemfile +12 -0
- data/gemfiles/rails_5_1.gemfile +12 -0
- data/gemfiles/rails_5_2.gemfile +12 -0
- data/gemfiles/rails_master.gemfile +14 -0
- data/lib/doorkeeper/config.rb +119 -46
- data/lib/doorkeeper/engine.rb +11 -7
- data/lib/doorkeeper/errors.rb +18 -0
- data/lib/doorkeeper/grape/helpers.rb +14 -8
- data/lib/doorkeeper/helpers/controller.rb +8 -19
- data/lib/doorkeeper/models/access_grant_mixin.rb +10 -21
- data/lib/doorkeeper/models/access_token_mixin.rb +147 -43
- data/lib/doorkeeper/models/application_mixin.rb +33 -35
- data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +15 -5
- data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +6 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +37 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +22 -18
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
- data/lib/doorkeeper/oauth/authorization_code_request.rb +7 -5
- data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +9 -2
- data/lib/doorkeeper/oauth/base_response.rb +29 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +21 -8
- data/lib/doorkeeper/oauth/client.rb +2 -3
- 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.rb +2 -2
- data/lib/doorkeeper/oauth/error_response.rb +10 -10
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +17 -1
- data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -4
- data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -13
- data/lib/doorkeeper/oauth/pre_authorization.rb +5 -3
- data/lib/doorkeeper/oauth/refresh_token_request.rb +23 -14
- data/lib/doorkeeper/oauth/scopes.rb +18 -8
- data/lib/doorkeeper/oauth/token.rb +20 -21
- data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
- 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_grant.rb +27 -0
- data/lib/doorkeeper/orm/active_record/access_token.rb +34 -8
- data/lib/doorkeeper/orm/active_record/application.rb +48 -11
- data/lib/doorkeeper/orm/active_record.rb +17 -22
- data/lib/doorkeeper/rails/helpers.rb +6 -9
- data/lib/doorkeeper/rails/routes/mapper.rb +4 -4
- data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
- data/lib/doorkeeper/rails/routes.rb +17 -11
- data/lib/doorkeeper/request/authorization_code.rb +7 -1
- data/lib/doorkeeper/request/password.rb +2 -2
- data/lib/doorkeeper/request/refresh_token.rb +1 -1
- data/lib/doorkeeper/request.rb +7 -1
- data/lib/doorkeeper/server.rb +0 -8
- data/lib/doorkeeper/validations.rb +3 -2
- data/lib/doorkeeper/version.rb +34 -1
- data/lib/doorkeeper.rb +10 -2
- data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +31 -0
- data/lib/generators/doorkeeper/application_owner_generator.rb +11 -2
- data/lib/generators/doorkeeper/migration_generator.rb +13 -1
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +35 -0
- data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +11 -0
- data/{spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb → lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb} +1 -1
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +11 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +38 -6
- data/lib/generators/doorkeeper/templates/migration.rb.erb +69 -0
- data/spec/controllers/application_metal_controller.rb +10 -0
- data/spec/controllers/applications_controller_spec.rb +15 -4
- data/spec/controllers/authorizations_controller_spec.rb +74 -27
- data/spec/controllers/protected_resources_controller_spec.rb +70 -32
- data/spec/controllers/token_info_controller_spec.rb +17 -13
- data/spec/controllers/tokens_controller_spec.rb +198 -12
- 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/doorkeeper.rb +19 -3
- data/spec/dummy/config/initializers/new_framework_defaults.rb +6 -0
- data/spec/dummy/config/initializers/secret_token.rb +0 -1
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
- data/{lib/generators/doorkeeper/templates/migration.rb → spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb} +16 -4
- data/{lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb → spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb} +4 -2
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +13 -0
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb +13 -0
- data/spec/dummy/db/schema.rb +24 -22
- data/spec/factories.rb +4 -2
- data/spec/generators/application_owner_generator_spec.rb +24 -5
- data/spec/generators/migration_generator_spec.rb +24 -3
- data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
- data/spec/grape/grape_integration_spec.rb +135 -0
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
- data/spec/lib/config_spec.rb +159 -14
- 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 +55 -12
- data/spec/lib/oauth/base_request_spec.rb +155 -0
- data/spec/lib/oauth/base_response_spec.rb +45 -0
- data/spec/lib/oauth/client/credentials_spec.rb +45 -2
- data/spec/lib/oauth/client_credentials/creator_spec.rb +1 -1
- data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
- data/spec/lib/oauth/client_credentials_request_spec.rb +1 -0
- data/spec/lib/oauth/code_request_spec.rb +1 -3
- data/spec/lib/oauth/code_response_spec.rb +34 -0
- data/spec/lib/oauth/error_response_spec.rb +9 -9
- data/spec/lib/oauth/error_spec.rb +1 -1
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -1
- data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
- data/spec/lib/oauth/password_access_token_request_spec.rb +14 -8
- data/spec/lib/oauth/pre_authorization_spec.rb +12 -7
- data/spec/lib/oauth/refresh_token_request_spec.rb +52 -9
- data/spec/lib/oauth/scopes_spec.rb +28 -2
- data/spec/lib/oauth/token_request_spec.rb +6 -8
- data/spec/lib/oauth/token_spec.rb +12 -5
- data/spec/lib/server_spec.rb +10 -3
- data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
- data/spec/models/doorkeeper/access_token_spec.rb +116 -48
- data/spec/models/doorkeeper/application_spec.rb +145 -29
- data/spec/requests/applications/applications_request_spec.rb +5 -5
- data/spec/requests/endpoints/authorization_spec.rb +5 -6
- data/spec/requests/endpoints/token_spec.rb +8 -1
- data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
- data/spec/requests/flows/authorization_code_spec.rb +6 -13
- data/spec/requests/flows/client_credentials_spec.rb +29 -1
- data/spec/requests/flows/implicit_grant_errors_spec.rb +2 -2
- data/spec/requests/flows/password_spec.rb +118 -15
- data/spec/requests/flows/refresh_token_spec.rb +89 -19
- data/spec/requests/flows/revoke_token_spec.rb +105 -91
- data/spec/requests/protected_resources/metal_spec.rb +1 -1
- data/spec/requests/protected_resources/private_api_spec.rb +1 -1
- data/spec/routing/custom_controller_routes_spec.rb +4 -0
- data/spec/routing/default_routes_spec.rb +5 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/spec_helper_integration.rb +22 -4
- data/spec/support/dependencies/factory_girl.rb +2 -2
- data/spec/support/helpers/access_token_request_helper.rb +1 -1
- data/spec/support/helpers/model_helper.rb +34 -7
- data/spec/support/helpers/request_spec_helper.rb +17 -5
- data/spec/support/helpers/url_helper.rb +9 -8
- data/spec/support/http_method_shim.rb +38 -0
- data/spec/support/shared/controllers_shared_context.rb +15 -10
- data/spec/support/shared/models_shared_examples.rb +5 -5
- data/spec/validators/redirect_uri_validator_spec.rb +51 -6
- data/spec/version/version_spec.rb +15 -0
- metadata +128 -46
- 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/20130902165751_create_doorkeeper_tables.rb +0 -41
- data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
- data/spec/lib/oauth/client/methods_spec.rb +0 -54
data/lib/doorkeeper/engine.rb
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
module Doorkeeper
|
2
2
|
class Engine < Rails::Engine
|
3
3
|
initializer "doorkeeper.params.filter" do |app|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
initializer "doorkeeper.locales" do |app|
|
8
|
-
if app.config.i18n.fallbacks.blank?
|
9
|
-
app.config.i18n.fallbacks = [:en]
|
10
|
-
end
|
4
|
+
parameters = %w[client_secret code authentication_token access_token refresh_token]
|
5
|
+
app.config.filter_parameters << /^(#{Regexp.union parameters})$/
|
11
6
|
end
|
12
7
|
|
13
8
|
initializer "doorkeeper.routes" do
|
@@ -19,5 +14,14 @@ module Doorkeeper
|
|
19
14
|
include Doorkeeper::Rails::Helpers
|
20
15
|
end
|
21
16
|
end
|
17
|
+
|
18
|
+
if defined?(Sprockets) && Sprockets::VERSION.chr.to_i >= 4
|
19
|
+
initializer 'doorkeeper.assets.precompile' do |app|
|
20
|
+
app.config.assets.precompile += %w[
|
21
|
+
doorkeeper/application.css
|
22
|
+
doorkeeper/admin/application.css
|
23
|
+
]
|
24
|
+
end
|
25
|
+
end
|
22
26
|
end
|
23
27
|
end
|
data/lib/doorkeeper/errors.rb
CHANGED
@@ -1,21 +1,39 @@
|
|
1
1
|
module Doorkeeper
|
2
2
|
module Errors
|
3
3
|
class DoorkeeperError < StandardError
|
4
|
+
def type
|
5
|
+
message
|
6
|
+
end
|
4
7
|
end
|
5
8
|
|
6
9
|
class InvalidAuthorizationStrategy < DoorkeeperError
|
10
|
+
def type
|
11
|
+
:unsupported_response_type
|
12
|
+
end
|
7
13
|
end
|
8
14
|
|
9
15
|
class InvalidTokenReuse < DoorkeeperError
|
16
|
+
def type
|
17
|
+
:invalid_request
|
18
|
+
end
|
10
19
|
end
|
11
20
|
|
12
21
|
class InvalidGrantReuse < DoorkeeperError
|
22
|
+
def type
|
23
|
+
:invalid_grant
|
24
|
+
end
|
13
25
|
end
|
14
26
|
|
15
27
|
class InvalidTokenStrategy < DoorkeeperError
|
28
|
+
def type
|
29
|
+
:unsupported_grant_type
|
30
|
+
end
|
16
31
|
end
|
17
32
|
|
18
33
|
class MissingRequestStrategy < DoorkeeperError
|
34
|
+
def type
|
35
|
+
:invalid_request
|
36
|
+
end
|
19
37
|
end
|
20
38
|
|
21
39
|
class UnableToGenerateToken < DoorkeeperError
|
@@ -3,12 +3,13 @@ require 'doorkeeper/grape/authorization_decorator'
|
|
3
3
|
module Doorkeeper
|
4
4
|
module Grape
|
5
5
|
module Helpers
|
6
|
+
# These helpers are for grape >= 0.10
|
6
7
|
extend ::Grape::API::Helpers
|
7
8
|
include Doorkeeper::Rails::Helpers
|
8
9
|
|
9
10
|
# endpoint specific scopes > parameter scopes > default scopes
|
10
11
|
def doorkeeper_authorize!(*scopes)
|
11
|
-
endpoint_scopes =
|
12
|
+
endpoint_scopes = endpoint.route_setting(:scopes) || endpoint.options[:route_options][:scopes]
|
12
13
|
scopes = if endpoint_scopes
|
13
14
|
Doorkeeper::OAuth::Scopes.from_array(endpoint_scopes)
|
14
15
|
elsif scopes && !scopes.empty?
|
@@ -19,18 +20,16 @@ module Doorkeeper
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def doorkeeper_render_error_with(error)
|
22
|
-
status_code =
|
23
|
-
when :unauthorized
|
24
|
-
401
|
25
|
-
when :forbidden
|
26
|
-
403
|
27
|
-
end
|
28
|
-
|
23
|
+
status_code = error_status_codes[error.status]
|
29
24
|
error!({ error: error.description }, status_code, error.headers)
|
30
25
|
end
|
31
26
|
|
32
27
|
private
|
33
28
|
|
29
|
+
def endpoint
|
30
|
+
env['api.endpoint']
|
31
|
+
end
|
32
|
+
|
34
33
|
def doorkeeper_token
|
35
34
|
@_doorkeeper_token ||= OAuth::Token.authenticate(
|
36
35
|
decorated_request,
|
@@ -41,6 +40,13 @@ module Doorkeeper
|
|
41
40
|
def decorated_request
|
42
41
|
AuthorizationDecorator.new(request)
|
43
42
|
end
|
43
|
+
|
44
|
+
def error_status_codes
|
45
|
+
{
|
46
|
+
unauthorized: 401,
|
47
|
+
forbidden: 403
|
48
|
+
}
|
49
|
+
end
|
44
50
|
end
|
45
51
|
end
|
46
52
|
end
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# Define methods that can be called in any controller that inherits from
|
2
|
+
# Doorkeeper::ApplicationMetalController or Doorkeeper::ApplicationController
|
1
3
|
module Doorkeeper
|
2
4
|
module Helpers
|
3
5
|
module Controller
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
6
|
private
|
7
7
|
|
8
|
+
# :doc:
|
8
9
|
def authenticate_resource_owner!
|
9
10
|
current_resource_owner
|
10
11
|
end
|
11
12
|
|
13
|
+
# :doc:
|
12
14
|
def current_resource_owner
|
13
15
|
instance_eval(&Doorkeeper.configuration.authenticate_resource_owner)
|
14
16
|
end
|
@@ -17,6 +19,7 @@ module Doorkeeper
|
|
17
19
|
instance_eval(&Doorkeeper.configuration.resource_owner_from_credentials)
|
18
20
|
end
|
19
21
|
|
22
|
+
# :doc:
|
20
23
|
def authenticate_admin!
|
21
24
|
instance_eval(&Doorkeeper.configuration.authenticate_admin)
|
22
25
|
end
|
@@ -25,6 +28,7 @@ module Doorkeeper
|
|
25
28
|
@server ||= Server.new(self)
|
26
29
|
end
|
27
30
|
|
31
|
+
# :doc:
|
28
32
|
def doorkeeper_token
|
29
33
|
@token ||= OAuth::Token.authenticate request, *config_methods
|
30
34
|
end
|
@@ -34,27 +38,12 @@ module Doorkeeper
|
|
34
38
|
end
|
35
39
|
|
36
40
|
def get_error_response_from_exception(exception)
|
37
|
-
|
38
|
-
when Errors::InvalidTokenStrategy
|
39
|
-
:unsupported_grant_type
|
40
|
-
when Errors::InvalidAuthorizationStrategy
|
41
|
-
:unsupported_response_type
|
42
|
-
when Errors::MissingRequestStrategy
|
43
|
-
:invalid_request
|
44
|
-
when Errors::InvalidTokenReuse
|
45
|
-
:invalid_request
|
46
|
-
when Errors::InvalidGrantReuse
|
47
|
-
:invalid_grant
|
48
|
-
when Errors::DoorkeeperError
|
49
|
-
exception.message
|
50
|
-
end
|
51
|
-
|
52
|
-
OAuth::ErrorResponse.new name: error_name, state: params[:state]
|
41
|
+
OAuth::ErrorResponse.new name: exception.type, state: params[:state]
|
53
42
|
end
|
54
43
|
|
55
44
|
def handle_token_exception(exception)
|
56
45
|
error = get_error_response_from_exception exception
|
57
|
-
|
46
|
+
headers.merge! error.headers
|
58
47
|
self.response_body = error.body.to_json
|
59
48
|
self.status = error.status
|
60
49
|
end
|
@@ -6,32 +6,21 @@ module Doorkeeper
|
|
6
6
|
include Models::Expirable
|
7
7
|
include Models::Revocable
|
8
8
|
include Models::Accessible
|
9
|
+
include Models::Orderable
|
9
10
|
include Models::Scopes
|
10
|
-
include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
|
11
|
-
|
12
|
-
included do
|
13
|
-
belongs_to :application, class_name: 'Doorkeeper::Application', inverse_of: :access_grants
|
14
|
-
|
15
|
-
if respond_to?(:attr_accessible)
|
16
|
-
attr_accessible :resource_owner_id, :application_id, :expires_in, :redirect_uri, :scopes
|
17
|
-
end
|
18
|
-
|
19
|
-
validates :resource_owner_id, :application_id, :token, :expires_in, :redirect_uri, presence: true
|
20
|
-
validates :token, uniqueness: true
|
21
|
-
|
22
|
-
before_validation :generate_token, on: :create
|
23
|
-
end
|
24
11
|
|
25
12
|
module ClassMethods
|
13
|
+
# Searches for Doorkeeper::AccessGrant record with the
|
14
|
+
# specific token value.
|
15
|
+
#
|
16
|
+
# @param token [#to_s] token value (any object that responds to `#to_s`)
|
17
|
+
#
|
18
|
+
# @return [Doorkeeper::AccessGrant, nil] AccessGrant object or nil
|
19
|
+
# if there is no record with such token
|
20
|
+
#
|
26
21
|
def by_token(token)
|
27
|
-
|
22
|
+
find_by(token: token.to_s)
|
28
23
|
end
|
29
24
|
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def generate_token
|
34
|
-
self.token = UniqueToken.generate
|
35
|
-
end
|
36
25
|
end
|
37
26
|
end
|
@@ -6,46 +6,64 @@ module Doorkeeper
|
|
6
6
|
include Models::Expirable
|
7
7
|
include Models::Revocable
|
8
8
|
include Models::Accessible
|
9
|
+
include Models::Orderable
|
9
10
|
include Models::Scopes
|
10
|
-
include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
|
11
|
-
|
12
|
-
included do
|
13
|
-
belongs_to :application,
|
14
|
-
class_name: 'Doorkeeper::Application',
|
15
|
-
inverse_of: :access_tokens
|
16
|
-
|
17
|
-
validates :token, presence: true, uniqueness: true
|
18
|
-
validates :refresh_token, uniqueness: true, if: :use_refresh_token?
|
19
|
-
|
20
|
-
attr_writer :use_refresh_token
|
21
|
-
|
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
|
-
before_validation :generate_token, on: :create
|
28
|
-
before_validation :generate_refresh_token,
|
29
|
-
on: :create,
|
30
|
-
if: :use_refresh_token?
|
31
|
-
end
|
32
11
|
|
33
12
|
module ClassMethods
|
13
|
+
# Returns an instance of the Doorkeeper::AccessToken with
|
14
|
+
# specific token value.
|
15
|
+
#
|
16
|
+
# @param token [#to_s]
|
17
|
+
# token value (any object that responds to `#to_s`)
|
18
|
+
#
|
19
|
+
# @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
|
20
|
+
# if there is no record with such token
|
21
|
+
#
|
34
22
|
def by_token(token)
|
35
|
-
|
23
|
+
find_by(token: token.to_s)
|
36
24
|
end
|
37
25
|
|
26
|
+
# Returns an instance of the Doorkeeper::AccessToken
|
27
|
+
# with specific token value.
|
28
|
+
#
|
29
|
+
# @param refresh_token [#to_s]
|
30
|
+
# refresh token value (any object that responds to `#to_s`)
|
31
|
+
#
|
32
|
+
# @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
|
33
|
+
# if there is no record with such refresh token
|
34
|
+
#
|
38
35
|
def by_refresh_token(refresh_token)
|
39
|
-
|
36
|
+
find_by(refresh_token: refresh_token.to_s)
|
40
37
|
end
|
41
38
|
|
42
|
-
|
39
|
+
# Revokes AccessToken records that have not been revoked and associated
|
40
|
+
# with the specific Application and Resource Owner.
|
41
|
+
#
|
42
|
+
# @param application_id [Integer]
|
43
|
+
# ID of the Application
|
44
|
+
# @param resource_owner [ActiveRecord::Base]
|
45
|
+
# instance of the Resource Owner model
|
46
|
+
#
|
47
|
+
def revoke_all_for(application_id, resource_owner, clock = Time)
|
43
48
|
where(application_id: application_id,
|
44
49
|
resource_owner_id: resource_owner.id,
|
45
50
|
revoked_at: nil).
|
46
|
-
|
51
|
+
update_all(revoked_at: clock.now.utc)
|
47
52
|
end
|
48
53
|
|
54
|
+
# Looking for not expired Access Token with a matching set of scopes
|
55
|
+
# that belongs to specific Application and Resource Owner.
|
56
|
+
#
|
57
|
+
# @param application [Doorkeeper::Application]
|
58
|
+
# Application instance
|
59
|
+
# @param resource_owner_or_id [ActiveRecord::Base, Integer]
|
60
|
+
# Resource Owner model instance or it's ID
|
61
|
+
# @param scopes [String, Doorkeeper::OAuth::Scopes]
|
62
|
+
# set of scopes
|
63
|
+
#
|
64
|
+
# @return [Doorkeeper::AccessToken, nil] Access Token instance or
|
65
|
+
# nil if matching record was not found
|
66
|
+
#
|
49
67
|
def matching_token_for(application, resource_owner_or_id, scopes)
|
50
68
|
resource_owner_id = if resource_owner_or_id.respond_to?(:to_key)
|
51
69
|
resource_owner_or_id.id
|
@@ -58,6 +76,19 @@ module Doorkeeper
|
|
58
76
|
end
|
59
77
|
end
|
60
78
|
|
79
|
+
# Checks whether the token scopes match the scopes from the parameters or
|
80
|
+
# Application scopes (if present).
|
81
|
+
#
|
82
|
+
# @param token_scopes [#to_s]
|
83
|
+
# set of scopes (any object that responds to `#to_s`)
|
84
|
+
# @param param_scopes [String]
|
85
|
+
# scopes from params
|
86
|
+
# @param app_scopes [String]
|
87
|
+
# Application scopes
|
88
|
+
#
|
89
|
+
# @return [Boolean] true if all scopes are blank or matches
|
90
|
+
# and false in other cases
|
91
|
+
#
|
61
92
|
def scopes_match?(token_scopes, param_scopes, app_scopes)
|
62
93
|
(!token_scopes.present? && !param_scopes.present?) ||
|
63
94
|
Doorkeeper::OAuth::Helpers::ScopeChecker.match?(
|
@@ -67,6 +98,23 @@ module Doorkeeper
|
|
67
98
|
)
|
68
99
|
end
|
69
100
|
|
101
|
+
# Looking for not expired AccessToken record with a matching set of
|
102
|
+
# scopes that belongs to specific Application and Resource Owner.
|
103
|
+
# If it doesn't exists - then creates it.
|
104
|
+
#
|
105
|
+
# @param application [Doorkeeper::Application]
|
106
|
+
# Application instance
|
107
|
+
# @param resource_owner_id [ActiveRecord::Base, Integer]
|
108
|
+
# Resource Owner model instance or it's ID
|
109
|
+
# @param scopes [#to_s]
|
110
|
+
# set of scopes (any object that responds to `#to_s`)
|
111
|
+
# @param expires_in [Integer]
|
112
|
+
# token lifetime in seconds
|
113
|
+
# @param use_refresh_token [Boolean]
|
114
|
+
# whether to use the refresh token
|
115
|
+
#
|
116
|
+
# @return [Doorkeeper::AccessToken] existing record or a new one
|
117
|
+
#
|
70
118
|
def find_or_create_for(application, resource_owner_id, scopes, expires_in, use_refresh_token)
|
71
119
|
if Doorkeeper.configuration.reuse_access_token
|
72
120
|
access_token = matching_token_for(application, resource_owner_id, scopes)
|
@@ -74,6 +122,7 @@ module Doorkeeper
|
|
74
122
|
return access_token
|
75
123
|
end
|
76
124
|
end
|
125
|
+
|
77
126
|
create!(
|
78
127
|
application_id: application.try(:id),
|
79
128
|
resource_owner_id: resource_owner_id,
|
@@ -83,60 +132,115 @@ module Doorkeeper
|
|
83
132
|
)
|
84
133
|
end
|
85
134
|
|
135
|
+
# Looking for not revoked Access Token record that belongs to specific
|
136
|
+
# Application and Resource Owner.
|
137
|
+
#
|
138
|
+
# @param application_id [Integer]
|
139
|
+
# ID of the Application model instance
|
140
|
+
# @param resource_owner_id [Integer]
|
141
|
+
# ID of the Resource Owner model instance
|
142
|
+
#
|
143
|
+
# @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
|
144
|
+
# nil if nothing was found
|
145
|
+
#
|
86
146
|
def last_authorized_token_for(application_id, resource_owner_id)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
limit(1).
|
92
|
-
to_a.
|
93
|
-
first
|
147
|
+
ordered_by(:created_at, :desc).
|
148
|
+
find_by(application_id: application_id,
|
149
|
+
resource_owner_id: resource_owner_id,
|
150
|
+
revoked_at: nil)
|
94
151
|
end
|
95
152
|
end
|
96
153
|
|
154
|
+
# Access Token type: Bearer.
|
155
|
+
# @see https://tools.ietf.org/html/rfc6750
|
156
|
+
# The OAuth 2.0 Authorization Framework: Bearer Token Usage
|
157
|
+
#
|
97
158
|
def token_type
|
98
|
-
'
|
159
|
+
'Bearer'
|
99
160
|
end
|
100
161
|
|
101
162
|
def use_refresh_token?
|
163
|
+
@use_refresh_token ||= false
|
102
164
|
!!@use_refresh_token
|
103
165
|
end
|
104
166
|
|
167
|
+
# JSON representation of the Access Token instance.
|
168
|
+
#
|
169
|
+
# @return [Hash] hash with token data
|
105
170
|
def as_json(_options = {})
|
106
171
|
{
|
107
172
|
resource_owner_id: resource_owner_id,
|
108
173
|
scopes: scopes,
|
109
174
|
expires_in_seconds: expires_in_seconds,
|
110
175
|
application: { uid: application.try(:uid) },
|
111
|
-
created_at: created_at.to_i
|
176
|
+
created_at: created_at.to_i
|
112
177
|
}
|
113
178
|
end
|
114
179
|
|
115
|
-
#
|
180
|
+
# Indicates whether the token instance have the same credential
|
181
|
+
# as the other Access Token.
|
182
|
+
#
|
183
|
+
# @param access_token [Doorkeeper::AccessToken] other token
|
184
|
+
#
|
185
|
+
# @return [Boolean] true if credentials are same of false in other cases
|
186
|
+
#
|
116
187
|
def same_credential?(access_token)
|
117
188
|
application_id == access_token.application_id &&
|
118
189
|
resource_owner_id == access_token.resource_owner_id
|
119
190
|
end
|
120
191
|
|
192
|
+
# Indicates if token is acceptable for specific scopes.
|
193
|
+
#
|
194
|
+
# @param scopes [Array<String>] scopes
|
195
|
+
#
|
196
|
+
# @return [Boolean] true if record is accessible and includes scopes or
|
197
|
+
# false in other cases
|
198
|
+
#
|
121
199
|
def acceptable?(scopes)
|
122
200
|
accessible? && includes_scope?(*scopes)
|
123
201
|
end
|
124
202
|
|
125
203
|
private
|
126
204
|
|
205
|
+
# Generates refresh token with UniqueToken generator.
|
206
|
+
#
|
207
|
+
# @return [String] refresh token value
|
208
|
+
#
|
127
209
|
def generate_refresh_token
|
128
|
-
|
210
|
+
self.refresh_token = UniqueToken.generate
|
129
211
|
end
|
130
212
|
|
213
|
+
# Generates and sets the token value with the
|
214
|
+
# configured Generator class (see Doorkeeper.configuration).
|
215
|
+
#
|
216
|
+
# @return [String] generated token value
|
217
|
+
#
|
218
|
+
# @raise [Doorkeeper::Errors::UnableToGenerateToken]
|
219
|
+
# custom class doesn't implement .generate method
|
220
|
+
# @raise [Doorkeeper::Errors::TokenGeneratorNotFound]
|
221
|
+
# custom class doesn't exist
|
222
|
+
#
|
131
223
|
def generate_token
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
224
|
+
self.created_at ||= Time.now.utc
|
225
|
+
|
226
|
+
self.token = token_generator.generate(
|
227
|
+
resource_owner_id: resource_owner_id,
|
228
|
+
scopes: scopes,
|
229
|
+
application: application,
|
230
|
+
expires_in: expires_in,
|
231
|
+
created_at: created_at
|
232
|
+
)
|
233
|
+
end
|
234
|
+
|
235
|
+
def token_generator
|
236
|
+
generator_name = Doorkeeper.configuration.access_token_generator
|
237
|
+
generator = generator_name.constantize
|
238
|
+
|
239
|
+
return generator if generator.respond_to?(:generate)
|
240
|
+
|
137
241
|
raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
|
138
242
|
rescue NameError
|
139
|
-
raise Errors::TokenGeneratorNotFound, "#{
|
243
|
+
raise Errors::TokenGeneratorNotFound, "#{generator_name} not found"
|
140
244
|
end
|
141
245
|
end
|
142
246
|
end
|
@@ -3,51 +3,49 @@ module Doorkeeper
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
include OAuth::Helpers
|
6
|
+
include Models::Orderable
|
6
7
|
include Models::Scopes
|
7
|
-
include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
|
8
|
-
|
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'
|
12
|
-
|
13
|
-
validates :name, :secret, :uid, presence: true
|
14
|
-
validates :uid, uniqueness: true
|
15
|
-
validates :redirect_uri, redirect_uri: true
|
16
|
-
|
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
|
-
end
|
23
8
|
|
24
9
|
module ClassMethods
|
10
|
+
# Returns an instance of the Doorkeeper::Application with
|
11
|
+
# specific UID and secret.
|
12
|
+
#
|
13
|
+
# Public/Non-confidential applications will only find by uid if secret is
|
14
|
+
# blank.
|
15
|
+
#
|
16
|
+
# @param uid [#to_s] UID (any object that responds to `#to_s`)
|
17
|
+
# @param secret [#to_s] secret (any object that responds to `#to_s`)
|
18
|
+
#
|
19
|
+
# @return [Doorkeeper::Application, nil] Application instance or nil
|
20
|
+
# if there is no record with such credentials
|
21
|
+
#
|
25
22
|
def by_uid_and_secret(uid, secret)
|
26
|
-
|
23
|
+
app = by_uid(uid)
|
24
|
+
return unless app
|
25
|
+
return app if secret.blank? && !app.confidential?
|
26
|
+
return unless app.secret == secret
|
27
|
+
app
|
27
28
|
end
|
28
29
|
|
30
|
+
# Returns an instance of the Doorkeeper::Application with specific UID.
|
31
|
+
#
|
32
|
+
# @param uid [#to_s] UID (any object that responds to `#to_s`)
|
33
|
+
#
|
34
|
+
# @return [Doorkeeper::Application, nil] Application instance or nil
|
35
|
+
# if there is no record with such UID
|
36
|
+
#
|
29
37
|
def by_uid(uid)
|
30
|
-
|
38
|
+
find_by(uid: uid.to_s)
|
31
39
|
end
|
32
40
|
end
|
33
41
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
def generate_uid
|
42
|
-
if uid.blank?
|
43
|
-
self.uid = UniqueToken.generate
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def generate_secret
|
48
|
-
if secret.blank?
|
49
|
-
self.secret = UniqueToken.generate
|
50
|
-
end
|
42
|
+
# Set an application's valid redirect URIs.
|
43
|
+
#
|
44
|
+
# @param uris [String, Array] Newline-separated string or array the URI(s)
|
45
|
+
#
|
46
|
+
# @return [String] The redirect URI(s) seperated by newlines.
|
47
|
+
def redirect_uri=(uris)
|
48
|
+
super(uris.is_a?(Array) ? uris.join("\n") : uris)
|
51
49
|
end
|
52
50
|
end
|
53
51
|
end
|
@@ -1,20 +1,30 @@
|
|
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 >
|
9
|
+
expires_in && Time.now.utc > expires_at
|
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 =
|
18
|
+
expires = expires_at - Time.now.utc
|
11
19
|
expires_sec = expires.seconds.round(0)
|
12
20
|
expires_sec > 0 ? expires_sec : 0
|
13
21
|
end
|
14
22
|
|
15
|
-
|
16
|
-
|
17
|
-
|
23
|
+
# Expiration time (date time of creation + TTL).
|
24
|
+
#
|
25
|
+
# @return [Time] expiration time in UTC
|
26
|
+
#
|
27
|
+
def expires_at
|
18
28
|
created_at + expires_in.seconds
|
19
29
|
end
|
20
30
|
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
|
|