diff --git a/app/controllers/doorkeeper/openid_connect/discovery_controller.rb b/app/controllers/doorkeeper/openid_connect/discovery_controller.rb new file mode 100644 index 0000000..8711660 --- /dev/null +++ b/app/controllers/doorkeeper/openid_connect/discovery_controller.rb @@ -0,0 +1,53 @@ +module Doorkeeper + module OpenidConnect + class DiscoveryController < ::Doorkeeper::ApplicationController + include Doorkeeper::Helpers::Controller + + def show + render json: provider_configuration + end + + private + + def provider_configuration + doorkeeper = ::Doorkeeper.configuration + openid_connect = ::Doorkeeper::OpenidConnect.configuration + + { + issuer: openid_connect.issuer, + authorization_endpoint: oauth_authorization_url(protocol: :https), + token_endpoint: oauth_token_url(protocol: :https), + userinfo_endpoint: oauth_userinfo_url(protocol: :https), + + # TODO: implement controller + #jwks_uri: oauth_keys_url(protocol: :https), + + scopes_supported: doorkeeper.scopes, + + # TODO: support id_token response type + response_types_supported: doorkeeper.authorization_response_types, + response_modes_supported: [ 'query', 'fragment' ], + + token_endpoint_auth_methods_supported: [ + 'client_secret_basic', + 'client_secret_post', + + # TODO: look into doorkeeper-jwt_assertion for these + #'client_secret_jwt', + #'private_key_jwt' + ], + + # TODO: make this configurable + subject_types_supported: [ + 'public', + ], + + # TODO: make this configurable + id_token_signing_alg_values_supported: [ + 'RS256', + ], + } + end + end + end +end diff --git a/lib/doorkeeper/openid_connect/rails/routes.rb b/lib/doorkeeper/openid_connect/rails/routes.rb index eaf74cd..3eb5d0e 100644 --- a/lib/doorkeeper/openid_connect/rails/routes.rb +++ b/lib/doorkeeper/openid_connect/rails/routes.rb @@ -26,6 +26,10 @@ def generate_routes!(options) routes.scope options[:scope] || 'oauth', as: 'oauth' do map_route(:userinfo, :userinfo_routes) end + + routes.scope as: 'oauth' do + map_route(:discovery, :discovery_routes) + end end private @@ -44,6 +48,15 @@ def userinfo_routes(mapping) controller: mapping[:controllers] ) end + + def discovery_routes(mapping) + routes.resource( + :discovery, + path: '.well-known/openid-configuration', + only: [:show], as: mapping[:as], + controller: mapping[:controllers] + ) + end end end end diff --git a/lib/doorkeeper/openid_connect/rails/routes/mapping.rb b/lib/doorkeeper/openid_connect/rails/routes/mapping.rb index f8609a3..7d5484e 100644 --- a/lib/doorkeeper/openid_connect/rails/routes/mapping.rb +++ b/lib/doorkeeper/openid_connect/rails/routes/mapping.rb @@ -7,11 +7,13 @@ class Mapping def initialize @controllers = { - userinfo: 'doorkeeper/openid_connect/userinfo' + userinfo: 'doorkeeper/openid_connect/userinfo', + discovery: 'doorkeeper/openid_connect/discovery' } @as = { - userinfo: :userinfo + userinfo: :userinfo, + discovery: :discovery } @skips = [] diff --git a/spec/controllers/doorkeeper/openid_connect/discovery_controller_spec.rb b/spec/controllers/doorkeeper/openid_connect/discovery_controller_spec.rb new file mode 100644 index 0000000..271ff61 --- /dev/null +++ b/spec/controllers/doorkeeper/openid_connect/discovery_controller_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::DiscoveryController, type: :controller do + describe '#show' do + it 'returns the provider configuration' do + get :show + configuration = JSON.parse(response.body) + + expect(configuration.sort).to eq({ + 'issuer' => 'dummy', + 'authorization_endpoint' => 'https://test.host/oauth/authorize', + 'token_endpoint' => 'https://test.host/oauth/token', + 'userinfo_endpoint' => 'https://test.host/oauth/userinfo', + + 'scopes_supported' => ['openid'], + + 'response_types_supported' => ['code'], + 'response_modes_supported' => ['query', 'fragment'], + + 'token_endpoint_auth_methods_supported' => [ + 'client_secret_basic', + 'client_secret_post', + ], + + 'subject_types_supported' => [ + 'public', + ], + + 'id_token_signing_alg_values_supported' => [ + 'RS256', + ], + }.sort) + end + end +end diff --git a/spec/dummy/config/initializers/doorkeeper_openid_connect.rb b/spec/dummy/config/initializers/doorkeeper_openid_connect.rb index f055eaf..4980c2a 100644 --- a/spec/dummy/config/initializers/doorkeeper_openid_connect.rb +++ b/spec/dummy/config/initializers/doorkeeper_openid_connect.rb @@ -1,4 +1,6 @@ Doorkeeper::OpenidConnect.configure do + issuer 'dummy' + resource_owner_from_access_token do |access_token| User.find_by(id: access_token.resource_owner_id) end diff --git a/spec/lib/doorkeeper/openid_connect/routes_spec.rb b/spec/lib/doorkeeper/openid_connect/routes_spec.rb new file mode 100644 index 0000000..6bcc4a5 --- /dev/null +++ b/spec/lib/doorkeeper/openid_connect/routes_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::Rails::Routes, type: :routing do + it 'maps userinfo#show' do + expect(get: 'oauth/userinfo').to route_to( + controller: 'doorkeeper/openid_connect/userinfo', + action: 'show' + ) + end + + it 'maps discovery#show' do + expect(get: '.well-known/openid-configuration').to route_to( + controller: 'doorkeeper/openid_connect/discovery', + action: 'show' + ) + end +end