doorkeeper-device_authorization_grant 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5231c51f4fc5f93284e30b08cc6188e4ac43cfecfd1908110597350ddd0c2cf7
4
- data.tar.gz: 8cc73d6fe81263c383290e7c2b68a477b6cd0f4b6c9873d9efcdd4493fc1242b
3
+ metadata.gz: '08caf432de1258cd6b0dab0346a332f0a49698e35838194e1e6e9f999d1a2ccc'
4
+ data.tar.gz: 98c6b042087cb1a1df1f84d4e9aca7327f2cb637eaee58729de53a0d76fd9900
5
5
  SHA512:
6
- metadata.gz: 8f67e3f89aad7ce4cfc2ac7d7c70d1dcb63b6129bb877592fe14e917c10cea626c5cabd3724fe427415215da4a965d81c042de7f615f861c76a32cb5a95272f1
7
- data.tar.gz: e4fefdce2c1662f05f48871c47927ddd46607de767652273e73c98120d4734cd2e1cb79c2ec045cd1536948d4584b475f57060124711ec0cffbb82bd81b69864
6
+ metadata.gz: 05dca92fad2e8ef88aae7d9739aa08c990dd5643c1ef4aab563b761d3afb1f08727efd2f508d45155e524943f9082203fa8e7019bd0829867a0c218266aa9fb8
7
+ data.tar.gz: c603c13d33a65616bd370dac83625396318ee7e47e0dc16f99cd620c23ebd5e1df0f9a30a6b7915eb33f85dd9ba7e2d2284793c0156808c86350591e97ae9085
data/README.md CHANGED
@@ -316,5 +316,12 @@ Content-Type: application/json
316
316
  The device authentication flow is now complete, and the token data can be used to
317
317
  authenticate requests against the authorization and/or resource server.
318
318
 
319
+ ## Example Application
320
+
321
+ Here you can find an example Rails application which uses this gem,
322
+ together with a little HTML/JS client to try out the device flow:
323
+
324
+ [https://github.com/exop-group/doorkeeper-device-flow-example](https://github.com/exop-group/doorkeeper-device-flow-example)
325
+
319
326
  ## License
320
327
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -9,6 +9,7 @@ module Doorkeeper
9
9
  # OAuth 2.0 Device Authorization Grant extension for Doorkeeper.
10
10
  module DeviceAuthorizationGrant
11
11
  autoload :DeviceGrant, 'doorkeeper/device_authorization_grant/orm/active_record/device_grant'
12
+ autoload :DeviceGrantMixin, 'doorkeeper/device_authorization_grant/orm/active_record/device_grant_mixin'
12
13
  autoload :Errors, 'doorkeeper/device_authorization_grant/errors'
13
14
  autoload :VERSION, 'doorkeeper/device_authorization_grant/version'
14
15
 
@@ -18,8 +18,10 @@ module Doorkeeper
18
18
  # Error raised in case of missing configuration
19
19
  class MissingConfiguration < StandardError
20
20
  def initialize
21
- super('Configuration for Doorkeeper::DeviceAuthorizationGrant missing. ' \
22
- 'Do you have Doorkeeper::DeviceAuthorizationGrant initializer?')
21
+ super(
22
+ 'Configuration for Doorkeeper::DeviceAuthorizationGrant missing. ' \
23
+ 'Do you have Doorkeeper::DeviceAuthorizationGrant initializer?'
24
+ )
23
25
  end
24
26
  end
25
27
 
@@ -7,8 +7,8 @@ module Doorkeeper
7
7
  #
8
8
  # @see https://tools.ietf.org/html/rfc8628#section-3.1 RFC 8628, sect. 3.1
9
9
  class DeviceAuthorizationRequest < Doorkeeper::OAuth::BaseRequest
10
- attr_accessor :server
11
- attr_accessor :client
10
+ attr_accessor :server,
11
+ :client
12
12
 
13
13
  # @return [String]
14
14
  attr_accessor :host_name
@@ -19,6 +19,7 @@ module Doorkeeper
19
19
  # @param client
20
20
  # @param host_name [String]
21
21
  def initialize(server, client, host_name)
22
+ super()
22
23
  @server = server
23
24
  @client = client
24
25
  @host_name = host_name
@@ -16,6 +16,7 @@ module Doorkeeper
16
16
  # @param device_grant [DeviceGrant]
17
17
  # @param host_name [String]
18
18
  def initialize(device_grant, host_name)
19
+ super()
19
20
  @device_grant = device_grant
20
21
  @host_name = host_name
21
22
  end
@@ -7,14 +7,13 @@ module Doorkeeper
7
7
  #
8
8
  # @see https://tools.ietf.org/html/rfc8628#section-3.4 RFC 8628, sect. 3.4
9
9
  class DeviceCodeRequest < ::Doorkeeper::OAuth::BaseRequest
10
- attr_accessor :server
11
- attr_accessor :client
10
+ attr_accessor :server,
11
+ :client,
12
+ :access_token
12
13
 
13
14
  # @return [DeviceGrant]
14
15
  attr_accessor :device_grant
15
16
 
16
- attr_accessor :access_token
17
-
18
17
  validate :client, error: :invalid_client
19
18
  validate :device_grant, error: :invalid_grant
20
19
 
@@ -22,6 +21,8 @@ module Doorkeeper
22
21
  # @param client
23
22
  # @param device_grant [DeviceGrant]
24
23
  def initialize(server, client, device_grant)
24
+ super()
25
+
25
26
  @server = server
26
27
  @client = client
27
28
  @device_grant = device_grant
@@ -5,41 +5,7 @@ module Doorkeeper
5
5
  # Model class, similar to Doorkeeper `AccessGrant`, but specific for
6
6
  # handling OAuth 2.0 Device Authorization Grant.
7
7
  class DeviceGrant < ActiveRecord::Base
8
- self.table_name = "#{table_name_prefix}oauth_device_grants#{table_name_suffix}"
9
-
10
- include ::Doorkeeper::Models::Expirable
11
-
12
- delegate :secret_strategy, :fallback_secret_strategy, to: :class
13
-
14
- belongs_to :application, class_name: Doorkeeper.configuration.application_class, optional: true
15
-
16
- before_validation :generate_device_code, on: :create
17
-
18
- validates :application_id, presence: true
19
- validates :expires_in, presence: true
20
- validates :device_code, presence: true, uniqueness: true
21
-
22
- validates :user_code, presence: true, uniqueness: true, if: -> { resource_owner_id.blank? }
23
- validates :user_code, absence: true, if: -> { resource_owner_id.present? }
24
-
25
- validates :resource_owner_id, presence: true, if: -> { user_code.blank? }
26
- validates :resource_owner_id, absence: true, if: -> { user_code.present? }
27
-
28
- scope(
29
- :expired,
30
- lambda do
31
- exp_in = DeviceAuthorizationGrant.configuration.device_code_expires_in
32
- where('created_at <= :expiration_date', expiration_date: exp_in.seconds.ago)
33
- end
34
- )
35
-
36
- scope(
37
- :unexpired,
38
- lambda do
39
- exp_in = DeviceAuthorizationGrant.configuration.device_code_expires_in
40
- where('created_at > :expiration_date', expiration_date: exp_in.seconds.ago)
41
- end
42
- )
8
+ include DeviceGrantMixin
43
9
 
44
10
  # @!attribute application_id
45
11
  # @return [Integer]
@@ -64,87 +30,6 @@ module Doorkeeper
64
30
 
65
31
  # @!attribute last_polling_at
66
32
  # @return [Time, nil]
67
-
68
- class << self
69
- # Returns an instance of the DeviceGrant with specific device code
70
- # value.
71
- #
72
- # @param device_code [#to_s] device code value
73
- # @return [Doorkeeper::DeviceAuthorizationGrant::DeviceGrant, nil]
74
- # DeviceGrant object, or nil if there is no record with such code
75
- def find_by_plaintext_device_code(device_code)
76
- device_code = device_code.to_s
77
-
78
- find_by(device_code: secret_strategy.transform_secret(device_code)) ||
79
- find_by_fallback_device_code(device_code)
80
- end
81
-
82
- alias by_device_code find_by_plaintext_device_code
83
-
84
- # Allow looking up previously plain device codes as a fallback IFF a
85
- # fallback strategy has been defined
86
- #
87
- # @param plain_secret [#to_s] plain secret value
88
- # @return [Doorkeeper::DeviceAuthorizationGrant::DeviceGrant, nil]
89
- # DeviceGrant object or nil if there is no record with such code
90
- def find_by_fallback_device_code(plain_secret)
91
- return nil unless fallback_secret_strategy
92
-
93
- # Use the previous strategy to look up
94
- stored_code = fallback_secret_strategy.transform_secret(plain_secret)
95
- find_by(device_code: stored_code).tap do |resource|
96
- upgrade_fallback_value(resource, plain_secret) if resource
97
- end
98
- end
99
-
100
- # Allows to replace a plain value fallback, to avoid it remaining as
101
- # plain text.
102
- #
103
- # @param instance [Doorkeeper::DeviceAuthorizationGrant::DeviceGrant]
104
- # An instance of this model with a plain value device code.
105
- # @param plain_secret [String] The plain secret to upgrade.
106
- def upgrade_fallback_value(instance, plain_secret)
107
- upgraded =
108
- secret_strategy.store_secret(instance, :device_code, plain_secret)
109
- instance.update(device_code: upgraded)
110
- end
111
-
112
- # Determines the secret storing transformer
113
- # Unless configured otherwise, uses the plain secret strategy
114
- def secret_strategy
115
- ::Doorkeeper.configuration.token_secret_strategy
116
- end
117
-
118
- # Determine the fallback storing strategy
119
- # Unless configured, there will be no fallback
120
- def fallback_secret_strategy
121
- ::Doorkeeper.configuration.token_secret_fallback_strategy
122
- end
123
- end
124
-
125
- # We keep a volatile copy of the raw device code for initial
126
- # communication.
127
- #
128
- # Some strategies allow restoring stored secrets (e.g. symmetric
129
- # encryption) while hashing strategies do not, so you cannot rely on
130
- # this value returning a present value for persisted device codes.
131
- def plaintext_device_code
132
- if secret_strategy.allows_restoring_secrets?
133
- secret_strategy.restore_secret(self, :device_code)
134
- else
135
- @raw_device_code
136
- end
137
- end
138
-
139
- private
140
-
141
- # Generates a device code value with UniqueToken class.
142
- #
143
- # @return [String] device code value
144
- def generate_device_code
145
- @raw_device_code = Doorkeeper::OAuth::Helpers::UniqueToken.generate
146
- secret_strategy.store_secret(self, :device_code, @raw_device_code)
147
- end
148
33
  end
149
34
  end
150
35
  end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module DeviceAuthorizationGrant
5
+ # Module mixin for Device Grant models.
6
+ #
7
+ # This is similar to Doorkeeper `AccessGrantMixin`, but specific for handling
8
+ # OAuth 2.0 Device Authorization Grant.
9
+ module DeviceGrantMixin
10
+ extend ActiveSupport::Concern
11
+ include ::Doorkeeper::Models::Expirable
12
+
13
+ included do
14
+ self.table_name = "#{table_name_prefix}oauth_device_grants#{table_name_suffix}"
15
+
16
+ delegate :secret_strategy, :fallback_secret_strategy, to: :class
17
+
18
+ belongs_to :application, class_name: Doorkeeper.configuration.application_class, optional: true
19
+
20
+ before_validation :generate_device_code, on: :create
21
+
22
+ validates :application_id, presence: true
23
+ validates :expires_in, presence: true
24
+ validates :device_code, presence: true, uniqueness: true
25
+
26
+ validates :user_code, presence: true, uniqueness: true, if: -> { resource_owner_id.blank? }
27
+ validates :user_code, absence: true, if: -> { resource_owner_id.present? }
28
+
29
+ validates :resource_owner_id, presence: true, if: -> { user_code.blank? }
30
+ validates :resource_owner_id, absence: true, if: -> { user_code.present? }
31
+
32
+ scope(
33
+ :expired,
34
+ lambda do
35
+ exp_in = DeviceAuthorizationGrant.configuration.device_code_expires_in
36
+ where('created_at <= :expiration_date', expiration_date: exp_in.seconds.ago)
37
+ end
38
+ )
39
+
40
+ scope(
41
+ :unexpired,
42
+ lambda do
43
+ exp_in = DeviceAuthorizationGrant.configuration.device_code_expires_in
44
+ where('created_at > :expiration_date', expiration_date: exp_in.seconds.ago)
45
+ end
46
+ )
47
+ end
48
+
49
+ # ClassMethods
50
+ module ClassMethods
51
+ # Returns an instance of the DeviceGrant with specific device code
52
+ # value.
53
+ #
54
+ # @param device_code [#to_s] device code value
55
+ # @return [Doorkeeper::DeviceAuthorizationGrant::DeviceGrant, nil]
56
+ # DeviceGrant object, or nil if there is no record with such code
57
+ def find_by_plaintext_device_code(device_code)
58
+ device_code = device_code.to_s
59
+
60
+ find_by(device_code: secret_strategy.transform_secret(device_code)) ||
61
+ find_by_fallback_device_code(device_code)
62
+ end
63
+
64
+ alias by_device_code find_by_plaintext_device_code
65
+
66
+ # Allow looking up previously plain device codes as a fallback IFF a
67
+ # fallback strategy has been defined
68
+ #
69
+ # @param plain_secret [#to_s] plain secret value
70
+ # @return [Doorkeeper::DeviceAuthorizationGrant::DeviceGrant, nil]
71
+ # DeviceGrant object or nil if there is no record with such code
72
+ def find_by_fallback_device_code(plain_secret)
73
+ return nil unless fallback_secret_strategy
74
+
75
+ # Use the previous strategy to look up
76
+ stored_code = fallback_secret_strategy.transform_secret(plain_secret)
77
+ find_by(device_code: stored_code).tap do |resource|
78
+ upgrade_fallback_value(resource, plain_secret) if resource
79
+ end
80
+ end
81
+
82
+ # Allows to replace a plain value fallback, to avoid it remaining as
83
+ # plain text.
84
+ #
85
+ # @param instance [Doorkeeper::DeviceAuthorizationGrant::DeviceGrant]
86
+ # An instance of this model with a plain value device code.
87
+ # @param plain_secret [String] The plain secret to upgrade.
88
+ def upgrade_fallback_value(instance, plain_secret)
89
+ upgraded =
90
+ secret_strategy.store_secret(instance, :device_code, plain_secret)
91
+ instance.update(device_code: upgraded)
92
+ end
93
+
94
+ # Determines the secret storing transformer
95
+ # Unless configured otherwise, uses the plain secret strategy
96
+ def secret_strategy
97
+ ::Doorkeeper.configuration.token_secret_strategy
98
+ end
99
+
100
+ # Determine the fallback storing strategy
101
+ # Unless configured, there will be no fallback
102
+ def fallback_secret_strategy
103
+ ::Doorkeeper.configuration.token_secret_fallback_strategy
104
+ end
105
+ end
106
+
107
+ # We keep a volatile copy of the raw device code for initial
108
+ # communication.
109
+ #
110
+ # Some strategies allow restoring stored secrets (e.g. symmetric
111
+ # encryption) while hashing strategies do not, so you cannot rely on
112
+ # this value returning a present value for persisted device codes.
113
+ def plaintext_device_code
114
+ if secret_strategy.allows_restoring_secrets?
115
+ secret_strategy.restore_secret(self, :device_code)
116
+ else
117
+ @raw_device_code
118
+ end
119
+ end
120
+
121
+ private
122
+
123
+ # Generates a device code value with UniqueToken class.
124
+ #
125
+ # @return [String] device code value
126
+ def generate_device_code
127
+ @raw_device_code = Doorkeeper::OAuth::Helpers::UniqueToken.generate
128
+ secret_strategy.store_secret(self, :device_code, @raw_device_code)
129
+ end
130
+ end
131
+ end
132
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Doorkeeper
4
4
  module DeviceAuthorizationGrant
5
- VERSION = '0.1.1'
5
+ VERSION = '0.2.0'
6
6
  public_constant :VERSION
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doorkeeper-device_authorization_grant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - EXOP Group
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-30 00:00:00.000000000 Z
11
+ date: 2021-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: doorkeeper
@@ -30,56 +30,70 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.86.0
33
+ version: '1.8'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.86.0
40
+ version: '1.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.9.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.9.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: simplecov
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: 0.18.5
61
+ version: 0.21.1
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: 0.18.5
68
+ version: 0.21.1
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: sqlite3
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '1.3'
75
+ version: 1.4.2
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '1.3'
82
+ version: 1.4.2
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: yard
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: 0.9.25
89
+ version: 0.9.26
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: 0.9.25
96
+ version: 0.9.26
83
97
  description: OAuth 2.0 Device Authorization Grant extension for Doorkeeper.
84
98
  email:
85
99
  - opensource@exop-group.com
@@ -105,6 +119,7 @@ files:
105
119
  - lib/doorkeeper/device_authorization_grant/oauth/helpers/user_code.rb
106
120
  - lib/doorkeeper/device_authorization_grant/orm/active_record.rb
107
121
  - lib/doorkeeper/device_authorization_grant/orm/active_record/device_grant.rb
122
+ - lib/doorkeeper/device_authorization_grant/orm/active_record/device_grant_mixin.rb
108
123
  - lib/doorkeeper/device_authorization_grant/rails/routes.rb
109
124
  - lib/doorkeeper/device_authorization_grant/rails/routes/mapper.rb
110
125
  - lib/doorkeeper/device_authorization_grant/rails/routes/mapping.rb