Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump doorkeeper 5.5 and define body method for authorization response to support response_mode=form_post #138

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Unreleased

- [#138] Support form_post response mode (This gem now requires Doorkeeper v5.5)

## v1.7.5 (2020-12-15)

### Changes
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The following parts of [OpenID Connect Core 1.0](http://openid.net/specs/openid-
- [Requesting Claims using Scope Values](http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims)
- [UserInfo Endpoint](http://openid.net/specs/openid-connect-core-1_0.html#UserInfo)
- [Normal Claims](http://openid.net/specs/openid-connect-core-1_0.html#NormalClaims)
- [OAuth 2.0 Form Post Response Mode](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html)

In addition we also support most of [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) for automatic configuration discovery.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def provider_response

# TODO: support id_token response type
response_types_supported: doorkeeper.authorization_response_types,
response_modes_supported: %w[query fragment],
response_modes_supported: response_modes_supported(doorkeeper),
grant_types_supported: grant_types_supported(doorkeeper),

# TODO: look into doorkeeper-jwt_assertion for these
Expand Down Expand Up @@ -76,6 +76,10 @@ def grant_types_supported(doorkeeper)
grant_types_supported
end

def response_modes_supported(doorkeeper)
doorkeeper.authorization_response_flows.flat_map(&:response_mode_matches).uniq
end

def webfinger_response
{
subject: params.require(:resource),
Expand Down
2 changes: 1 addition & 1 deletion doorkeeper-openid_connect.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = '>= 2.4'

spec.add_runtime_dependency 'doorkeeper', '>= 5.2', '< 5.5'
spec.add_runtime_dependency 'doorkeeper', '>= 5.5', '< 5.6'
toupeira marked this conversation as resolved.
Show resolved Hide resolved
spec.add_runtime_dependency 'json-jwt', '>= 1.11.0'

spec.add_development_dependency 'conventional-changelog', '~> 1.2'
Expand Down
12 changes: 5 additions & 7 deletions lib/doorkeeper/oauth/id_token_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,17 @@ def redirectable?
true
end

def redirect_uri
Authorization::URIBuilder.uri_with_fragment(pre_auth.redirect_uri, redirect_uri_params)
end

private

def redirect_uri_params
def body
{
expires_in: auth.token.expires_in_seconds,
state: pre_auth.state,
id_token: id_token.as_jws_token
}
end

def redirect_uri
Authorization::URIBuilder.uri_with_fragment(pre_auth.redirect_uri, body)
end
end
end
end
4 changes: 1 addition & 3 deletions lib/doorkeeper/oauth/id_token_token_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
module Doorkeeper
module OAuth
class IdTokenTokenResponse < IdTokenResponse
private

def redirect_uri_params
def body
super.merge({
access_token: auth.token.token,
token_type: auth.token.token_type
Expand Down
36 changes: 15 additions & 21 deletions lib/doorkeeper/openid_connect.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@
require 'doorkeeper/openid_connect/claims/claim'
require 'doorkeeper/openid_connect/claims/normal_claim'
require 'doorkeeper/openid_connect/config'
require 'doorkeeper/openid_connect/response_types_config'
require 'doorkeeper/openid_connect/engine'
require 'doorkeeper/openid_connect/errors'
require 'doorkeeper/openid_connect/id_token'
require 'doorkeeper/openid_connect/id_token_token'
require 'doorkeeper/openid_connect/user_info'
require 'doorkeeper/openid_connect/response_mode'
require 'doorkeeper/openid_connect/version'

require 'doorkeeper/openid_connect/helpers/controller'
Expand Down Expand Up @@ -65,26 +63,22 @@ def self.signing_key_normalized
end
end

if defined?(::Doorkeeper::GrantFlow)
Doorkeeper::GrantFlow.register(
:id_token,
response_type_matches: 'id_token',
response_type_strategy: Doorkeeper::OpenidConnect::IdToken,
)
Doorkeeper::GrantFlow.register(
:id_token,
response_type_matches: 'id_token',
response_mode_matches: %w[fragment form_post],
response_type_strategy: Doorkeeper::OpenidConnect::IdToken,
)

Doorkeeper::GrantFlow.register(
'id_token token',
response_type_matches: 'id_token token',
response_type_strategy: Doorkeeper::OpenidConnect::IdTokenToken,
)
Doorkeeper::GrantFlow.register(
'id_token token',
response_type_matches: 'id_token token',
response_mode_matches: %w[fragment form_post],
response_type_strategy: Doorkeeper::OpenidConnect::IdTokenToken,
)

Doorkeeper::GrantFlow.register_alias(
'implicit_oidc', as: ['implicit', 'id_token', 'id_token token']
)
else
# TODO: drop this and corresponding file when we will set minimal
# required Doorkeeper version to 5.5.
Doorkeeper::Config.prepend OpenidConnect::ResponseTypeConfig
end
Doorkeeper::GrantFlow.register_alias(
'implicit_oidc', as: ['implicit', 'id_token', 'id_token token']
)
end
end
13 changes: 7 additions & 6 deletions lib/doorkeeper/openid_connect/helpers/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,16 @@ def handle_oidc_error!(exception)
redirect_uri: params[:redirect_uri],
response_on_fragment: pre_auth.response_on_fragment?,
)
end
end

response.headers.merge!(error_response.headers)

if error_response.redirectable?
render json: error_response.body, status: :found, location: error_response.redirect_uri
else
render json: error_response.body, status: error_response.status
end
# NOTE: Assign error_response to @authorize_response then use redirect_or_render method that are defined at
# doorkeeper's authorizations_controller.
# - https://github.com/doorkeeper-gem/doorkeeper/blob/v5.5.0/app/controllers/doorkeeper/authorizations_controller.rb#L110
# - https://github.com/doorkeeper-gem/doorkeeper/blob/v5.5.0/app/controllers/doorkeeper/authorizations_controller.rb#L52
@authorize_response = error_response
redirect_or_render(@authorize_response)
end

def handle_oidc_prompt_param!(owner)
Expand Down
25 changes: 9 additions & 16 deletions lib/doorkeeper/openid_connect/oauth/pre_authorization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,20 @@ module PreAuthorization
attr_reader :nonce

def initialize(server, attrs = {}, resource_owner = nil)
if (Doorkeeper::VERSION::MAJOR >= 5 && Doorkeeper::VERSION::MINOR >= 4) ||
Doorkeeper::VERSION::MAJOR >= 6
super
else
super(server, attrs)
end
super
@nonce = attrs[:nonce]
end

# This method will be updated when doorkeeper move to version > 5.2.2
# TODO: delete this method and refactor response_on_fragment? method (below) when doorkeeper gem version constrains is > 5.2.2
def error_response
if error == :invalid_request
Doorkeeper::OAuth::InvalidRequestResponse.from_request(self, response_on_fragment: response_on_fragment?)
else
Doorkeeper::OAuth::ErrorResponse.from_request(self, response_on_fragment: response_on_fragment?)
# NOTE: Auto get default response_mode of specified response_type if response_mode is not
# yet present. We can delete this method after Doorkeeper's minimize version support it.
def response_on_fragment?
return response_mode == 'fragment' if response_mode.present?

grant_flow = server.authorization_response_flows.detect do |flow|
flow.matches_response_type?(response_type)
end
end

def response_on_fragment?
Doorkeeper::OpenidConnect::ResponseMode.new(response_type).fragment?
grant_flow&.default_response_mode == 'fragment'
end
end
end
Expand Down
30 changes: 0 additions & 30 deletions lib/doorkeeper/openid_connect/response_mode.rb

This file was deleted.

17 changes: 0 additions & 17 deletions lib/doorkeeper/openid_connect/response_types_config.rb

This file was deleted.

35 changes: 34 additions & 1 deletion spec/controllers/discovery_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

'scopes_supported' => ['openid'],
'response_types_supported' => ['code', 'token', 'id_token', 'id_token token'],
'response_modes_supported' => %w[query fragment],
'response_modes_supported' => %w[query fragment form_post],
'grant_types_supported' => %w[authorization_code client_credentials implicit_oidc],

'token_endpoint_auth_methods_supported' => %w[client_secret_basic client_secret_post],
Expand Down Expand Up @@ -65,6 +65,39 @@
end
end

context 'when grant_flows is configed with only client_credentials' do
before { Doorkeeper.configure { grant_flows %w[client_credentials] } }

it 'return empty response_modes_supported' do
get :provider
data = JSON.parse(response.body)

expect(data['response_modes_supported']).to eq []
end
end

context 'when grant_flows is configed only implicit flow' do
before { Doorkeeper.configure { grant_flows %w[implicit_oidc] } }

it 'return fragment and form_post as response_modes_supported' do
get :provider
data = JSON.parse(response.body)

expect(data['response_modes_supported']).to eq %w[fragment form_post]
end
end

context 'when grant_flows is configed with authorization_code and implicit flow' do
before { Doorkeeper.configure { grant_flows %w[authorization_code implicit_oidc] } }

it 'return query, fragment and form_post as response_modes_supported' do
get :provider
data = JSON.parse(response.body)

expect(data['response_modes_supported']).to eq %w[query fragment form_post]
end
end

it 'uses the protocol option for generating URLs' do
Doorkeeper::OpenidConnect.configure do
protocol { :testing }
Expand Down
Loading