doorkeeper-sequel 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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