doorkeeper-sequel 1.4.0 → 1.5.0

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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +1 -0
  3. data/CHANGELOG.md +6 -0
  4. data/README.md +4 -3
  5. data/Rakefile +1 -0
  6. data/config/locales/en.yml +1 -0
  7. data/doorkeeper-sequel.gemspec +1 -2
  8. data/lib/doorkeeper-sequel.rb +12 -7
  9. data/lib/doorkeeper-sequel/gem_version.rb +1 -1
  10. data/lib/doorkeeper-sequel/generators/confidential_applications_generator.rb +14 -0
  11. data/lib/doorkeeper-sequel/generators/templates/add_confidential_to_application_migration.rb +7 -0
  12. data/lib/doorkeeper-sequel/generators/templates/create_doorkeeper_tables.rb +1 -0
  13. data/lib/doorkeeper-sequel/mixins/access_grant_mixin.rb +46 -0
  14. data/lib/doorkeeper-sequel/mixins/access_token_mixin.rb +164 -0
  15. data/lib/doorkeeper-sequel/mixins/application_mixin.rb +93 -0
  16. data/lib/doorkeeper-sequel/mixins/concerns/ownership.rb +15 -0
  17. data/lib/doorkeeper-sequel/mixins/concerns/sequel_compat.rb +63 -0
  18. data/lib/doorkeeper-sequel/validators/redirect_uri_validator.rb +65 -0
  19. data/lib/doorkeeper/orm/sequel.rb +2 -3
  20. data/lib/doorkeeper/orm/sequel/access_grant.rb +1 -3
  21. data/lib/doorkeeper/orm/sequel/access_token.rb +1 -8
  22. data/lib/doorkeeper/orm/sequel/application.rb +5 -3
  23. data/spec/stubs/config/initializers/db.rb +1 -0
  24. data/spec/stubs/models/user.rb +1 -1
  25. metadata +62 -36
  26. data/lib/doorkeeper/orm/sequel/models/access_grant_mixin.rb +0 -50
  27. data/lib/doorkeeper/orm/sequel/models/access_token_mixin.rb +0 -168
  28. data/lib/doorkeeper/orm/sequel/models/application_mixin.rb +0 -70
  29. data/lib/doorkeeper/orm/sequel/models/concerns/ownership.rb +0 -19
  30. data/lib/doorkeeper/orm/sequel/models/concerns/sequel_compat.rb +0 -59
  31. data/lib/doorkeeper/orm/sequel/validators/redirect_uri_validator.rb +0 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5180553fee8bec58a28e43b6c0f7640710f3361a
4
- data.tar.gz: 29edb05d561f410d413528b11d0e4ffd98def9e3
3
+ metadata.gz: 553728671816109cbf8e780da862de70222768b0
4
+ data.tar.gz: c241ff98bec1bef3de150659beebcc4b73853ad4
5
5
  SHA512:
6
- metadata.gz: 55f0fb88ffa48a2deadf38515930893f44ba79da1518ae0d9a8f33a4497c19373fe722315a4c58514ac2f7ac6c43312016183cdc9890a72d0d0594433ded4c5b
7
- data.tar.gz: 224719b1699ac988ba11841dace04acd0f9dd5cce79bb9f7798dedf5f07951e41693300225580b787214b6047c3a38a96e33286d2c7d00dde47c94757d2cc159
6
+ metadata.gz: d98ed140d5c131fbfc3d1967199c1a664baf9e6f2d2e398415fe52ad3e316c599f524bf6f058d9bbdd85c3f11cc17544a3eef7f78f41c39a63b86c8bb47c1225
7
+ data.tar.gz: 9fb3f5c993b40d5ef0a85dfe6ffbbd5b806ed74c5f3adaeb51429c8fbbe0f78a6f01c6de0de7f2633fe88ab00f260d595a1567d41a777547a4f3952924fdacdb
@@ -1,3 +1,4 @@
1
1
  [submodule "doorkeeper"]
2
2
  path = doorkeeper
3
3
  url = https://github.com/doorkeeper-gem/doorkeeper.git
4
+ branch = 4.4.0
@@ -6,6 +6,12 @@ Reverse Chronological Order:
6
6
 
7
7
  https://github.com/nbulaj/doorkeeper-sequel/compare/1.3.2...master
8
8
 
9
+ ## `1.5.0` (2018-10-03)
10
+
11
+ https://github.com/nbulaj/doorkeeper-sequel/compare/1.5.0...1.4.0
12
+
13
+ * Support Doorkeeper >= 4.2.7 && < 5.0.0
14
+
9
15
  ## `1.4.0` (2018-02-08)
10
16
 
11
17
  https://github.com/nbulaj/doorkeeper-sequel/compare/1.3.1...1.4.0
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Doorkeeper Sequel ORM extension
2
- [![GitHub release](https://img.shields.io/github/release/nbulaj/doorkeeper-sequel.svg?maxAge=259200)](https://github.com/nbulaj/doorkeeper-sequel/releases)
2
+ [![Gem Version](https://badge.fury.io/rb/doorkeeper-sequel.svg)](https://rubygems.org/gems/doorkeeper-sequel)
3
3
  [![Build Status](https://travis-ci.org/nbulaj/doorkeeper-sequel.svg?branch=master)](https://travis-ci.org/nbulaj/doorkeeper-sequel)
4
- [![Dependency Status](https://gemnasium.com/nbulaj/doorkeeper-sequel.svg)](https://gemnasium.com/nbulaj/doorkeeper-sequel)
5
4
  [![Code Climate](https://codeclimate.com/github/nbulaj/doorkeeper-sequel/badges/gpa.svg)](https://codeclimate.com/github/nbulaj/doorkeeper-sequel)
6
5
  [![License](http://img.shields.io/badge/license-MIT-brightgreen.svg)](#license)
7
6
 
@@ -18,7 +17,8 @@
18
17
  To start using the Doorkeeper Sequel ORM, add to your Gemfile:
19
18
 
20
19
  ``` ruby
21
- gem 'doorkeeper-sequel', '~> 1.3'
20
+ gem 'doorkeeper', '~> 4.0'
21
+ gem 'doorkeeper-sequel', '~> 1.4'
22
22
  ```
23
23
 
24
24
  Or you can use git `master` branch for the latest gem version:
@@ -41,6 +41,7 @@ Generate migrations:
41
41
  rake doorkeeper_sequel:generate:migration
42
42
  rake doorkeeper_sequel:generate:application_owner
43
43
  rake doorkeeper_sequel:generate:previous_refresh_token
44
+ rake doorkeeper_sequel:generate:confidential_applications # for Doorkeeper >= 4.4
44
45
  ```
45
46
 
46
47
  ## Tests
data/Rakefile CHANGED
@@ -32,6 +32,7 @@ class ExtensionIntegrator
32
32
  FileUtils.cp_r('spec/stubs/support/sequel.rb', 'spec/support/orm/sequel.rb')
33
33
  FileUtils.rm('spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb', force: true)
34
34
  FileUtils.rm('spec/dummy/config/initializers/new_framework_defaults.rb', force: true)
35
+ FileUtils.rm('spec/models/doorkeeper/base_record_spec.rb', force: true)
35
36
  # Remove generators specs because we are using our own
36
37
  FileUtils.rm(Dir.glob('spec/generators/*.rb'))
37
38
  end
@@ -14,3 +14,4 @@ en:
14
14
  invalid_uri: 'must be a valid URI.'
15
15
  relative_uri: 'must be an absolute URI.'
16
16
  secured_uri: 'must be an HTTPS/SSL URI.'
17
+ forbidden_uri: 'is forbidden by the server.'
@@ -6,7 +6,6 @@ Gem::Specification.new do |gem|
6
6
  gem.name = 'doorkeeper-sequel'
7
7
  gem.version = DoorkeeperSequel.gem_version
8
8
  gem.authors = ['Nikita Bulai']
9
- gem.date = '2018-02-08'
10
9
  gem.email = ['bulajnikita@gmail.com']
11
10
  gem.homepage = 'http://github.com/nbulaj/doorkeeper-sequel'
12
11
  gem.summary = 'Doorkeeper Sequel ORM'
@@ -21,7 +20,7 @@ Gem::Specification.new do |gem|
21
20
 
22
21
  gem.required_ruby_version = '>= 2.0.0'
23
22
 
24
- gem.add_runtime_dependency 'doorkeeper', '~> 4.0', '>= 4.0.0'
23
+ gem.add_runtime_dependency 'doorkeeper', '>= 4.2.6', '< 5.0'
25
24
  gem.add_runtime_dependency 'sequel', '>= 4.0.0', '< 6'
26
25
  gem.add_runtime_dependency 'sequel_polymorphic', '~> 0.2', '< 1.0'
27
26
  gem.add_runtime_dependency 'thor', '>= 0.18', '< 6'
@@ -1,17 +1,22 @@
1
1
  require 'doorkeeper-sequel/version'
2
2
 
3
3
  if defined?(::Rails)
4
- require 'thor/group'
5
-
6
- require 'doorkeeper-sequel/generators/concerns/migration_actions'
7
- require 'doorkeeper-sequel/generators/application_owner_generator'
8
- require 'doorkeeper-sequel/generators/migration_generator'
9
- require 'doorkeeper-sequel/generators/previous_refresh_token_generator'
10
-
11
4
  require 'doorkeeper-sequel/railtie'
12
5
  end
13
6
 
14
7
  require 'doorkeeper'
8
+ require 'thor/group'
9
+
10
+ require 'doorkeeper-sequel/generators/concerns/migration_actions'
11
+ require 'doorkeeper-sequel/generators/application_owner_generator'
12
+ require 'doorkeeper-sequel/generators/migration_generator'
13
+ require 'doorkeeper-sequel/generators/previous_refresh_token_generator'
14
+
15
+ require 'doorkeeper-sequel/mixins/concerns/sequel_compat'
16
+ require 'doorkeeper-sequel/mixins/access_token_mixin'
17
+ require 'doorkeeper-sequel/mixins/access_grant_mixin'
18
+ require 'doorkeeper-sequel/mixins/application_mixin'
19
+
15
20
  require 'doorkeeper/orm/sequel'
16
21
 
17
22
  module DoorkeeperSequel
@@ -5,7 +5,7 @@ module DoorkeeperSequel
5
5
 
6
6
  module VERSION
7
7
  MAJOR = 1
8
- MINOR = 4
8
+ MINOR = 5
9
9
  TINY = 0
10
10
 
11
11
  STRING = [MAJOR, MINOR, TINY].compact.join('.')
@@ -0,0 +1,14 @@
1
+ module DoorkeeperSequel
2
+ class ConfidentialApplicationsGenerator < ::Thor::Group
3
+ include ::Thor::Actions
4
+ include MigrationActions
5
+
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ desc 'Add confidential column to Doorkeeper applications.'
9
+
10
+ def install
11
+ create_migration 'add_confidential_to_application_migration'
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table(:oauth_applications) do
4
+ add_column :confidential, TrueClass, null: false, default: true
5
+ end
6
+ end
7
+ end
@@ -9,6 +9,7 @@ Sequel.migration do
9
9
 
10
10
  column :scopes, String, size: 255, null: false, default: ''
11
11
  column :redirect_uri, String
12
+ column :confidential, TrueClass, null: false, default: true
12
13
 
13
14
  column :created_at, DateTime
14
15
  column :updated_at, DateTime
@@ -0,0 +1,46 @@
1
+ module DoorkeeperSequel
2
+ module AccessGrantMixin
3
+ extend ActiveSupport::Concern
4
+
5
+ include SequelCompat
6
+ include Doorkeeper::OAuth::Helpers
7
+ include Doorkeeper::Models::Expirable
8
+ include Doorkeeper::Models::Revocable
9
+ include Doorkeeper::Models::Accessible
10
+ include Doorkeeper::Models::Scopes
11
+
12
+ included do
13
+ plugin :validation_helpers
14
+ plugin :timestamps
15
+
16
+ many_to_one :application, class: 'Doorkeeper::Application'
17
+
18
+ set_allowed_columns :resource_owner_id, :application_id,
19
+ :expires_in, :redirect_uri, :scopes
20
+
21
+ def before_validation
22
+ generate_token if new?
23
+ super
24
+ end
25
+
26
+ def validate
27
+ super
28
+ validates_presence [:resource_owner_id, :application_id,
29
+ :token, :expires_in, :redirect_uri]
30
+ validates_unique [:token]
31
+ end
32
+ end
33
+
34
+ module ClassMethods
35
+ def by_token(token)
36
+ first(token: token.to_s)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def generate_token
43
+ self.token = UniqueToken.generate
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,164 @@
1
+ module DoorkeeperSequel
2
+ module AccessTokenMixin
3
+ extend ActiveSupport::Concern
4
+
5
+ include SequelCompat
6
+ include Doorkeeper::OAuth::Helpers
7
+ include Doorkeeper::Models::Expirable
8
+ include Doorkeeper::Models::Revocable
9
+ include Doorkeeper::Models::Accessible
10
+ include Doorkeeper::Models::Scopes
11
+
12
+ included do
13
+ plugin :validation_helpers
14
+ plugin :timestamps
15
+
16
+ many_to_one :application, class: 'Doorkeeper::Application'
17
+
18
+ attr_writer :use_refresh_token
19
+
20
+ set_allowed_columns :application_id, :resource_owner_id, :expires_in,
21
+ :scopes, :use_refresh_token, :previous_refresh_token
22
+
23
+ def before_validation
24
+ if new?
25
+ generate_token
26
+ generate_refresh_token if use_refresh_token?
27
+ end
28
+
29
+ super
30
+ end
31
+
32
+ def validate
33
+ super
34
+ validates_presence [:token]
35
+ validates_unique [:token]
36
+
37
+ validates_unique [:refresh_token] if use_refresh_token?
38
+ end
39
+
40
+ def application_id?
41
+ application_id.present?
42
+ end
43
+ end
44
+
45
+ module ClassMethods
46
+ def by_token(token)
47
+ first(token: token.to_s)
48
+ end
49
+
50
+ def by_refresh_token(refresh_token)
51
+ first(refresh_token: refresh_token.to_s)
52
+ end
53
+
54
+ def revoke_all_for(application_id, resource_owner, clock = Time)
55
+ where(application_id: application_id,
56
+ resource_owner_id: resource_owner.id,
57
+ revoked_at: nil)
58
+ .update(revoked_at: clock.now.utc)
59
+ end
60
+
61
+ def matching_token_for(application, resource_owner_or_id, scopes)
62
+ resource_owner_id = if resource_owner_or_id.respond_to?(:to_key)
63
+ resource_owner_or_id.id
64
+ else
65
+ resource_owner_or_id
66
+ end
67
+ token = last_authorized_token_for(application.try(:id), resource_owner_id)
68
+ if token && scopes_match?(token.scopes, scopes, application.try(:scopes))
69
+ token
70
+ end
71
+ end
72
+
73
+ def scopes_match?(token_scopes, param_scopes, app_scopes)
74
+ (token_scopes.blank? && param_scopes.blank?) ||
75
+ Doorkeeper::OAuth::Helpers::ScopeChecker.match?(
76
+ token_scopes.to_s,
77
+ param_scopes,
78
+ app_scopes
79
+ )
80
+ end
81
+
82
+ def find_or_create_for(application, resource_owner_id, scopes, expires_in, use_refresh_token)
83
+ if Doorkeeper.configuration.reuse_access_token
84
+ access_token = matching_token_for(application, resource_owner_id, scopes)
85
+ return access_token if access_token && !access_token.expired?
86
+ end
87
+
88
+ create!(
89
+ application_id: application.try(:id),
90
+ resource_owner_id: resource_owner_id,
91
+ scopes: scopes.to_s,
92
+ expires_in: expires_in,
93
+ use_refresh_token: use_refresh_token
94
+ )
95
+ end
96
+
97
+ def last_authorized_token_for(application_id, resource_owner_id)
98
+ where(application_id: application_id,
99
+ resource_owner_id: resource_owner_id,
100
+ revoked_at: nil)
101
+ .send(order_method, created_at_desc)
102
+ .first
103
+ end
104
+ end
105
+
106
+ def token_type
107
+ 'Bearer'
108
+ end
109
+
110
+ def use_refresh_token?
111
+ !!@use_refresh_token
112
+ end
113
+
114
+ def as_json(_options = {})
115
+ {
116
+ resource_owner_id: resource_owner_id,
117
+ scopes: scopes,
118
+ expires_in_seconds: expires_in_seconds,
119
+ application: { uid: application.try(:uid) },
120
+ created_at: created_at.to_i
121
+ }
122
+ end
123
+
124
+ # It indicates whether the tokens have the same credential
125
+ def same_credential?(access_token)
126
+ application_id == access_token.application_id &&
127
+ resource_owner_id == access_token.resource_owner_id
128
+ end
129
+
130
+ def acceptable?(scopes)
131
+ accessible? && includes_scope?(*scopes)
132
+ end
133
+
134
+ private
135
+
136
+ def generate_refresh_token
137
+ self[:refresh_token] = UniqueToken.generate
138
+ end
139
+
140
+ def generate_token
141
+ self[:created_at] ||= Time.now.utc
142
+
143
+ generator = token_generator
144
+ unless generator.respond_to?(:generate)
145
+ raise Doorkeeper::Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
146
+ end
147
+
148
+ self[:token] = generator.generate(
149
+ resource_owner_id: resource_owner_id,
150
+ scopes: scopes,
151
+ application: application,
152
+ expires_in: expires_in,
153
+ created_at: created_at
154
+ )
155
+ end
156
+
157
+ def token_generator
158
+ generator_name = Doorkeeper.configuration.access_token_generator
159
+ generator_name.constantize
160
+ rescue NameError
161
+ raise Doorkeeper::Errors::TokenGeneratorNotFound, "#{generator_name} not found"
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,93 @@
1
+ require_relative '../validators/redirect_uri_validator'
2
+
3
+ module DoorkeeperSequel
4
+ module ApplicationMixin
5
+ extend ActiveSupport::Concern
6
+
7
+ include SequelCompat
8
+ include Doorkeeper::OAuth::Helpers
9
+ include Doorkeeper::Models::Scopes
10
+ include DoorkeeperSequel::RedirectUriValidator
11
+
12
+ included do
13
+ plugin :validation_helpers
14
+ plugin :timestamps
15
+ plugin :association_dependencies
16
+
17
+ one_to_many :access_grants, class: 'Doorkeeper::AccessGrant'
18
+ one_to_many :access_tokens, class: 'Doorkeeper::AccessToken'
19
+
20
+ add_association_dependencies access_grants: :delete, access_tokens: :delete
21
+
22
+ set_allowed_columns :name, :redirect_uri, :scopes, :confidential
23
+
24
+ def before_validation
25
+ generate_uid
26
+ generate_secret
27
+ super
28
+ end
29
+
30
+ def validate
31
+ super
32
+ validates_presence [:name, :secret, :uid]
33
+ validates_unique [:uid]
34
+ validates_redirect_uri :redirect_uri
35
+ validates_includes [true, false], :confidential, allow_missing: true
36
+
37
+ if respond_to?(:validate_owner?)
38
+ validates_presence [:owner_id] if validate_owner?
39
+ end
40
+ end
41
+ end
42
+
43
+ module ClassMethods
44
+ def by_uid_and_secret(uid, secret)
45
+ app = by_uid(uid)
46
+ return unless app
47
+ return app if secret.blank? && !app.confidential?
48
+ return unless app.secret == secret
49
+ app
50
+ end
51
+
52
+ def by_uid(uid)
53
+ first(uid: uid.to_s)
54
+ end
55
+
56
+ def supports_confidentiality?
57
+ column_names.include?('confidential')
58
+ end
59
+
60
+ def column_names
61
+ columns.map(&:to_s)
62
+ end
63
+ end
64
+
65
+ # Fallback to existing, default behaviour of assuming all apps to be
66
+ # confidential if the migration hasn't been run
67
+ def confidential
68
+ return super if self.class.supports_confidentiality?
69
+
70
+ ActiveSupport::Deprecation.warn 'You are susceptible to security bug ' \
71
+ 'CVE-2018-1000211. Please follow instructions outlined in ' \
72
+ 'Doorkeeper::CVE_2018_1000211_WARNING'
73
+
74
+ true
75
+ end
76
+
77
+ alias_method :confidential?, :confidential
78
+
79
+ private
80
+
81
+ def has_scopes?
82
+ Doorkeeper::Application.columns.include?('scopes')
83
+ end
84
+
85
+ def generate_uid
86
+ self.uid = UniqueToken.generate if uid.blank? && new?
87
+ end
88
+
89
+ def generate_secret
90
+ self.secret = UniqueToken.generate if secret.blank? && new?
91
+ end
92
+ end
93
+ end