doorkeeper-openid_connect 1.7.0 → 1.7.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -2
  3. data/README.md +40 -0
  4. data/app/controllers/doorkeeper/authorizations_controller.rb +17 -0
  5. data/app/controllers/doorkeeper/openid_connect/discovery_controller.rb +48 -26
  6. data/app/controllers/doorkeeper/openid_connect/userinfo_controller.rb +5 -1
  7. data/config/locales/en.yml +1 -0
  8. data/lib/doorkeeper/oauth/id_token_request.rb +8 -12
  9. data/lib/doorkeeper/oauth/id_token_response.rb +2 -0
  10. data/lib/doorkeeper/oauth/id_token_token_request.rb +2 -0
  11. data/lib/doorkeeper/oauth/id_token_token_response.rb +2 -0
  12. data/lib/doorkeeper/openid_connect.rb +26 -1
  13. data/lib/doorkeeper/openid_connect/claims/aggregated_claim.rb +2 -0
  14. data/lib/doorkeeper/openid_connect/claims/claim.rb +6 -4
  15. data/lib/doorkeeper/openid_connect/claims/distributed_claim.rb +2 -0
  16. data/lib/doorkeeper/openid_connect/claims/normal_claim.rb +2 -0
  17. data/lib/doorkeeper/openid_connect/claims_builder.rb +3 -1
  18. data/lib/doorkeeper/openid_connect/config.rb +24 -10
  19. data/lib/doorkeeper/openid_connect/engine.rb +2 -0
  20. data/lib/doorkeeper/openid_connect/errors.rb +2 -1
  21. data/lib/doorkeeper/openid_connect/helpers/controller.rb +45 -29
  22. data/lib/doorkeeper/openid_connect/id_token.rb +4 -2
  23. data/lib/doorkeeper/openid_connect/id_token_token.rb +2 -0
  24. data/lib/doorkeeper/openid_connect/oauth/authorization/code.rb +25 -8
  25. data/lib/doorkeeper/openid_connect/oauth/authorization_code_request.rb +4 -2
  26. data/lib/doorkeeper/openid_connect/oauth/password_access_token_request.rb +3 -1
  27. data/lib/doorkeeper/openid_connect/oauth/pre_authorization.rb +24 -3
  28. data/lib/doorkeeper/openid_connect/oauth/token_response.rb +3 -1
  29. data/lib/doorkeeper/openid_connect/orm/active_record.rb +2 -0
  30. data/lib/doorkeeper/openid_connect/orm/active_record/access_grant.rb +3 -1
  31. data/lib/doorkeeper/openid_connect/orm/active_record/request.rb +5 -3
  32. data/lib/doorkeeper/openid_connect/rails/routes.rb +3 -1
  33. data/lib/doorkeeper/openid_connect/rails/routes/mapper.rb +2 -0
  34. data/lib/doorkeeper/openid_connect/rails/routes/mapping.rb +2 -0
  35. data/lib/doorkeeper/openid_connect/response_mode.rb +30 -0
  36. data/lib/doorkeeper/openid_connect/response_types_config.rb +2 -2
  37. data/lib/doorkeeper/openid_connect/user_info.rb +2 -0
  38. data/lib/doorkeeper/openid_connect/version.rb +3 -1
  39. data/lib/doorkeeper/request/id_token.rb +2 -0
  40. data/lib/doorkeeper/request/id_token_token.rb +2 -0
  41. data/lib/generators/doorkeeper/openid_connect/install_generator.rb +4 -2
  42. data/lib/generators/doorkeeper/openid_connect/migration_generator.rb +3 -1
  43. data/lib/generators/doorkeeper/openid_connect/templates/initializer.rb +19 -5
  44. data/lib/generators/doorkeeper/openid_connect/templates/migration.rb.erb +3 -2
  45. metadata +35 -36
  46. data/.gitignore +0 -8
  47. data/.ruby-version +0 -1
  48. data/.travis.yml +0 -27
  49. data/CONTRIBUTING.md +0 -45
  50. data/Gemfile +0 -8
  51. data/Rakefile +0 -24
  52. data/bin/console +0 -9
  53. data/bin/setup +0 -8
  54. data/doorkeeper-openid_connect.gemspec +0 -32
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  module Claims
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ostruct'
2
4
 
3
5
  module Doorkeeper
@@ -31,7 +33,7 @@ module Doorkeeper
31
33
  generator: block
32
34
  )
33
35
  end
34
- alias_method :claim, :normal_claim
36
+ alias claim normal_claim
35
37
  end
36
38
  end
37
39
  end
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  def self.configure(&block)
4
6
  if Doorkeeper.configuration.orm != :active_record
5
- fail Errors::InvalidConfiguration, 'Doorkeeper OpenID Connect currently only supports the ActiveRecord ORM adapter'
7
+ raise Errors::InvalidConfiguration, 'Doorkeeper OpenID Connect currently only supports the ActiveRecord ORM adapter'
6
8
  end
7
9
 
8
10
  @config = Config::Builder.new(&block).build
9
11
  end
10
12
 
11
13
  def self.configuration
12
- @config || (fail Errors::MissingConfiguration)
14
+ @config || (raise Errors::MissingConfiguration)
13
15
  end
14
16
 
15
17
  class Config
@@ -23,12 +25,12 @@ module Doorkeeper
23
25
  @config
24
26
  end
25
27
 
26
- def jws_public_key(*args)
27
- puts "DEPRECATION WARNING: `jws_public_key` is not needed anymore and will be removed in a future version, please remove it from config/initializers/doorkeeper_openid_connect.rb"
28
+ def jws_public_key(*_args)
29
+ puts 'DEPRECATION WARNING: `jws_public_key` is not needed anymore and will be removed in a future version, please remove it from config/initializers/doorkeeper_openid_connect.rb'
28
30
  end
29
31
 
30
32
  def jws_private_key(*args)
31
- puts "DEPRECATION WARNING: `jws_private_key` has been replaced by `signing_key` and will be removed in a future version, please remove it from config/initializers/doorkeeper_openid_connect.rb"
33
+ puts 'DEPRECATION WARNING: `jws_private_key` has been replaced by `signing_key` and will be removed in a future version, please remove it from config/initializers/doorkeeper_openid_connect.rb'
32
34
  signing_key(*args)
33
35
  end
34
36
  end
@@ -71,7 +73,7 @@ module Doorkeeper
71
73
  value = if attribute_builder
72
74
  attribute_builder.new(&block).build
73
75
  else
74
- block ? block : args.first
76
+ block || args.first
75
77
  end
76
78
 
77
79
  @config.instance_variable_set(:"@#{attribute}", value)
@@ -102,19 +104,23 @@ module Doorkeeper
102
104
  option :subject_types_supported, default: [:public]
103
105
 
104
106
  option :resource_owner_from_access_token, default: lambda { |*_|
105
- fail Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.resource_owner_from_access_token_not_configured')
107
+ raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.resource_owner_from_access_token_not_configured')
106
108
  }
107
109
 
108
110
  option :auth_time_from_resource_owner, default: lambda { |*_|
109
- fail Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.auth_time_from_resource_owner_not_configured')
111
+ raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.auth_time_from_resource_owner_not_configured')
110
112
  }
111
113
 
112
114
  option :reauthenticate_resource_owner, default: lambda { |*_|
113
- fail Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.reauthenticate_resource_owner_not_configured')
115
+ raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.reauthenticate_resource_owner_not_configured')
116
+ }
117
+
118
+ option :select_account_for_resource_owner, default: lambda { |*_|
119
+ raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.select_account_for_resource_owner_not_configured')
114
120
  }
115
121
 
116
122
  option :subject, default: lambda { |*_|
117
- fail Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.subject_not_configured')
123
+ raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.subject_not_configured')
118
124
  }
119
125
 
120
126
  option :expiration, default: 120
@@ -124,6 +130,14 @@ module Doorkeeper
124
130
  option :protocol, default: lambda { |*_|
125
131
  ::Rails.env.production? ? :https : :http
126
132
  }
133
+
134
+ option :end_session_endpoint, default: lambda { |*_|
135
+ nil
136
+ }
137
+
138
+ option :discovery_url_options, default: lambda { |*_|
139
+ {}
140
+ }
127
141
  end
128
142
  end
129
143
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  class Engine < ::Rails::Engine
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  module Errors
@@ -24,7 +26,6 @@ module Doorkeeper
24
26
  class LoginRequired < OpenidConnectError; end
25
27
  class ConsentRequired < OpenidConnectError; end
26
28
  class InteractionRequired < OpenidConnectError; end
27
- class AccountSelectionRequired < OpenidConnectError; end
28
29
  end
29
30
  end
30
31
  end
@@ -1,9 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  module Helpers
4
6
  module Controller
5
7
  private
6
8
 
9
+ # FIXME: remove after Doorkeeper will merge it
10
+ def current_resource_owner
11
+ return @current_resource_owner if defined?(@current_resource_owner)
12
+
13
+ super
14
+ end
15
+
7
16
  def authenticate_resource_owner!
8
17
  super.tap do |owner|
9
18
  next unless oidc_authorization_request?
@@ -11,15 +20,14 @@ module Doorkeeper
11
20
  handle_oidc_prompt_param!(owner)
12
21
  handle_oidc_max_age_param!(owner)
13
22
  end
14
- rescue Errors::OpenidConnectError => exception
15
- handle_oidc_error!(exception)
23
+ rescue Errors::OpenidConnectError => e
24
+ handle_oidc_error!(e)
16
25
  end
17
26
 
18
27
  def oidc_authorization_request?
19
28
  controller_path == Doorkeeper::Rails::Routes.mapping[:authorizations][:controllers] &&
20
29
  action_name == 'new' &&
21
30
  pre_auth.valid? &&
22
- pre_auth.client &&
23
31
  pre_auth.scopes.include?('openid')
24
32
  end
25
33
 
@@ -31,17 +39,19 @@ module Doorkeeper
31
39
  @_response_body = nil
32
40
 
33
41
  error_response = if exception.type == :invalid_request
34
- ::Doorkeeper::OAuth::InvalidRequestResponse.new(
35
- name: exception.type,
36
- state: params[:state],
37
- redirect_uri: params[:redirect_uri],
38
- )
39
- else
40
- ::Doorkeeper::OAuth::ErrorResponse.new(
41
- name: exception.type,
42
- state: params[:state],
43
- redirect_uri: params[:redirect_uri],
44
- )
42
+ ::Doorkeeper::OAuth::InvalidRequestResponse.new(
43
+ name: exception.type,
44
+ state: params[:state],
45
+ redirect_uri: params[:redirect_uri],
46
+ response_on_fragment: pre_auth.response_on_fragment?,
47
+ )
48
+ else
49
+ ::Doorkeeper::OAuth::ErrorResponse.new(
50
+ name: exception.type,
51
+ state: params[:state],
52
+ redirect_uri: params[:redirect_uri],
53
+ response_on_fragment: pre_auth.response_on_fragment?,
54
+ )
45
55
  end
46
56
 
47
57
  response.headers.merge!(error_response.headers)
@@ -59,16 +69,15 @@ module Doorkeeper
59
69
  prompt_values.each do |prompt|
60
70
  case prompt
61
71
  when 'none'
62
- raise Errors::InvalidRequest if (prompt_values - [ 'none' ]).any?
72
+ raise Errors::InvalidRequest if (prompt_values - ['none']).any?
63
73
  raise Errors::LoginRequired unless owner
64
- raise Errors::ConsentRequired if oidc_consent_required?(owner)
74
+ raise Errors::ConsentRequired if oidc_consent_required?
65
75
  when 'login'
66
76
  reauthenticate_oidc_resource_owner(owner) if owner
67
77
  when 'consent'
68
78
  render :new
69
79
  when 'select_account'
70
- # TODO: let the user implement this
71
- raise Errors::AccountSelectionRequired
80
+ select_account_for_oidc_resource_owner(owner)
72
81
  else
73
82
  raise Errors::InvalidRequest
74
83
  end
@@ -89,36 +98,43 @@ module Doorkeeper
89
98
  end
90
99
  end
91
100
 
92
- def reauthenticate_oidc_resource_owner(owner)
101
+ def return_without_oidc_prompt_param(prompt_value)
93
102
  return_to = URI.parse(request.path)
94
103
  return_to.query = request.query_parameters.tap do |params|
95
- params['prompt'] = params['prompt'].to_s.sub(/\blogin\s*\b/, '').strip
104
+ params['prompt'] = params['prompt'].to_s.sub(/\b#{prompt_value}\s*\b/, '').strip
96
105
  params.delete('prompt') if params['prompt'].blank?
97
106
  end.to_query
107
+ return_to.to_s
108
+ end
109
+
110
+ def reauthenticate_oidc_resource_owner(owner)
111
+ return_to = return_without_oidc_prompt_param('login')
98
112
 
99
113
  instance_exec(
100
114
  owner,
101
- return_to.to_s,
115
+ return_to,
102
116
  &Doorkeeper::OpenidConnect.configuration.reauthenticate_resource_owner
103
117
  )
104
118
 
105
119
  raise Errors::LoginRequired unless performed?
106
120
  end
107
121
 
108
- def matching_tokens_for_oidc_resource_owner(owner)
109
- Doorkeeper::AccessToken.authorized_tokens_for(pre_auth.client.id, owner.id).select do |token|
110
- Doorkeeper::AccessToken.scopes_match?(token.scopes, pre_auth.scopes, pre_auth.client.scopes)
111
- end
122
+ def oidc_consent_required?
123
+ !skip_authorization? && !matching_token?
112
124
  end
113
125
 
114
- def oidc_consent_required?(owner)
115
- return false if skip_authorization?
126
+ def select_account_for_oidc_resource_owner(owner)
127
+ return_to = return_without_oidc_prompt_param('select_account')
116
128
 
117
- matching_tokens_for_oidc_resource_owner(owner).blank?
129
+ instance_exec(
130
+ owner,
131
+ return_to,
132
+ &Doorkeeper::OpenidConnect.configuration.select_account_for_resource_owner
133
+ )
118
134
  end
119
135
  end
120
136
  end
121
137
  end
122
138
 
123
- Helpers::Controller.send :prepend, OpenidConnect::Helpers::Controller
139
+ Helpers::Controller.prepend OpenidConnect::Helpers::Controller
124
140
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  class IdToken
@@ -9,7 +11,7 @@ module Doorkeeper
9
11
  @access_token = access_token
10
12
  @nonce = nonce
11
13
  @resource_owner = Doorkeeper::OpenidConnect.configuration.resource_owner_from_access_token.call(access_token)
12
- @issued_at = Time.now
14
+ @issued_at = Time.zone.now
13
15
  end
14
16
 
15
17
  def claims
@@ -46,7 +48,7 @@ module Doorkeeper
46
48
  end
47
49
 
48
50
  def audience
49
- @access_token.application.uid
51
+ @access_token.application.try(:uid)
50
52
  end
51
53
 
52
54
  def expiration
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  class IdTokenToken < IdToken
@@ -1,22 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  module OAuth
4
6
  module Authorization
5
7
  module Code
6
- def issue_token
7
- super.tap do |access_grant|
8
- if pre_auth.nonce.present?
9
- ::Doorkeeper::OpenidConnect::Request.create!(
10
- access_grant: access_grant,
11
- nonce: pre_auth.nonce
12
- )
8
+ if Doorkeeper::OAuth::Authorization::Code.method_defined?(:issue_token!)
9
+ def issue_token!
10
+ super.tap do |access_grant|
11
+ create_openid_request(access_grant) if pre_auth.nonce.present?
12
+ end
13
+ end
14
+
15
+ alias issue_token issue_token!
16
+ else
17
+ # FIXME: drop this after dropping support of Doorkeeper < 5.4
18
+ def issue_token
19
+ super.tap do |access_grant|
20
+ create_openid_request(access_grant) if pre_auth.nonce.present?
13
21
  end
14
22
  end
15
23
  end
24
+
25
+ private
26
+
27
+ def create_openid_request(access_grant)
28
+ ::Doorkeeper::OpenidConnect::Request.create!(
29
+ access_grant: access_grant,
30
+ nonce: pre_auth.nonce
31
+ )
32
+ end
16
33
  end
17
34
  end
18
35
  end
19
36
  end
20
37
 
21
- OAuth::Authorization::Code.send :prepend, OpenidConnect::OAuth::Authorization::Code
38
+ OAuth::Authorization::Code.prepend OpenidConnect::OAuth::Authorization::Code
22
39
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  module OAuth
@@ -8,7 +10,7 @@ module Doorkeeper
8
10
  super
9
11
 
10
12
  nonce =
11
- if openid_request = grant.openid_request
13
+ if (openid_request = grant.openid_request)
12
14
  openid_request.destroy!
13
15
  openid_request.nonce
14
16
  end
@@ -20,5 +22,5 @@ module Doorkeeper
20
22
  end
21
23
  end
22
24
 
23
- OAuth::AuthorizationCodeRequest.send :prepend, OpenidConnect::OAuth::AuthorizationCodeRequest
25
+ OAuth::AuthorizationCodeRequest.prepend OpenidConnect::OAuth::AuthorizationCodeRequest
24
26
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  module OAuth
@@ -20,5 +22,5 @@ module Doorkeeper
20
22
  end
21
23
  end
22
24
 
23
- OAuth::PasswordAccessTokenRequest.send :prepend, OpenidConnect::OAuth::PasswordAccessTokenRequest
25
+ OAuth::PasswordAccessTokenRequest.prepend OpenidConnect::OAuth::PasswordAccessTokenRequest
24
26
  end
@@ -1,16 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  module OAuth
4
6
  module PreAuthorization
5
7
  attr_reader :nonce
6
8
 
7
- def initialize(server, attrs = {})
8
- super
9
+ def initialize(server, attrs = {}, resource_owner = nil)
10
+ if (Doorkeeper::VERSION::MAJOR >= 5 && Doorkeeper::VERSION::MINOR >= 4) ||
11
+ Doorkeeper::VERSION::MAJOR >= 6
12
+ super
13
+ else
14
+ super(server, attrs)
15
+ end
9
16
  @nonce = attrs[:nonce]
10
17
  end
18
+
19
+ # This method will be updated when doorkeeper move to version > 5.2.2
20
+ # TODO: delete this method and refactor response_on_fragment? method (below) when doorkeeper gem version constrains is > 5.2.2
21
+ def error_response
22
+ if error == :invalid_request
23
+ Doorkeeper::OAuth::InvalidRequestResponse.from_request(self, response_on_fragment: response_on_fragment?)
24
+ else
25
+ Doorkeeper::OAuth::ErrorResponse.from_request(self, response_on_fragment: response_on_fragment?)
26
+ end
27
+ end
28
+
29
+ def response_on_fragment?
30
+ Doorkeeper::OpenidConnect::ResponseMode.new(response_type).fragment?
31
+ end
11
32
  end
12
33
  end
13
34
  end
14
35
 
15
- OAuth::PreAuthorization.send :prepend, OpenidConnect::OAuth::PreAuthorization
36
+ OAuth::PreAuthorization.prepend OpenidConnect::OAuth::PreAuthorization
16
37
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  module OAuth
@@ -19,5 +21,5 @@ module Doorkeeper
19
21
  end
20
22
  end
21
23
 
22
- OAuth::TokenResponse.send :prepend, OpenidConnect::OAuth::TokenResponse
24
+ OAuth::TokenResponse.prepend OpenidConnect::OAuth::TokenResponse
23
25
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/lazy_load_hooks'
2
4
 
3
5
  module Doorkeeper
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OpenidConnect
3
5
  module AccessGrant
@@ -12,5 +14,5 @@ module Doorkeeper
12
14
  end
13
15
  end
14
16
 
15
- AccessGrant.send :prepend, OpenidConnect::AccessGrant
17
+ AccessGrant.prepend OpenidConnect::AccessGrant
16
18
  end