From fba2ade75fb4344ff360e5512fd2c0b034e83a23 Mon Sep 17 00:00:00 2001 From: Nikita Bulai Date: Wed, 30 Jan 2019 14:59:25 +0300 Subject: [PATCH] Allow to customize Token Introspection response --- NEWS.md | 1 + lib/doorkeeper/config.rb | 15 +++++++---- lib/doorkeeper/oauth/token_introspection.rb | 17 ++++++++++-- .../doorkeeper/templates/initializer.rb | 16 +++++++++++ spec/controllers/tokens_controller_spec.rb | 27 +++++++++++++++++++ 5 files changed, 69 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index a128c91fa..5400950fc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,7 @@ User-visible changes worth mentioning. ## master +- [#1195] Allow to customize Token Introspection response (fix [#1194]). - [#1189] Option to set `token_reuse_limit`. - [#1191] Try to load bcrypt for hashing of application secrets, but add fallback. diff --git a/lib/doorkeeper/config.rb b/lib/doorkeeper/config.rb index 4d57fae48..59d3a11e4 100644 --- a/lib/doorkeeper/config.rb +++ b/lib/doorkeeper/config.rb @@ -261,11 +261,16 @@ def option(name, options = {}) nil end) - option :before_successful_authorization, default: ->(_context) {} - option :after_successful_authorization, default: ->(_context) {} - option :before_successful_strategy_response, default: ->(_request) {} - option :after_successful_strategy_response, - default: ->(_request, _response) {} + + # Hooks for authorization + option :before_successful_authorization, default: ->(_context) {} + option :after_successful_authorization, default: ->(_context) {} + # Hooks for strategies responses + option :before_successful_strategy_response, default: ->(_request) {} + option :after_successful_strategy_response, default: ->(_request, _response) {} + # Allows to customize Token Introspection response + option :custom_introspection_response, default: ->(_token, _context) { {} } + option :skip_authorization, default: ->(_routes) {} option :access_token_expires_in, default: 7200 option :custom_access_token_expires_in, default: ->(_context) { nil } diff --git a/lib/doorkeeper/oauth/token_introspection.rb b/lib/doorkeeper/oauth/token_introspection.rb index a87371ccd..fa4300274 100644 --- a/lib/doorkeeper/oauth/token_introspection.rb +++ b/lib/doorkeeper/oauth/token_introspection.rb @@ -60,14 +60,14 @@ def authorized_token # 2.2. Introspection Response def success_response - { + customize_response( active: true, scope: @token.scopes_string, client_id: @token.try(:application).try(:uid), token_type: @token.token_type, exp: @token.expires_at.to_i, iat: @token.created_at.to_i - } + ) end # If the introspection call is properly authorized but the token is not @@ -125,6 +125,19 @@ def authorized_for_client? true end end + + # Allows to customize introspection response. + # Provides context (controller) and token for generating developer-specific + # response. + def customize_response(response) + customized_response = Doorkeeper.configuration.custom_introspection_response.call( + token, + server.context + ) + return response if customized_response.blank? + + response.merge(customized_response) + end end end end diff --git a/lib/generators/doorkeeper/templates/initializer.rb b/lib/generators/doorkeeper/templates/initializer.rb index bc22f969a..b51516ccf 100644 --- a/lib/generators/doorkeeper/templates/initializer.rb +++ b/lib/generators/doorkeeper/templates/initializer.rb @@ -219,6 +219,22 @@ # # handle_auth_errors :raise + # Customize token introspection response. + # Allows to add your own fields to the introspection response + # (like `sub`, `aud` and so on). Can be a proc, lambda or any object responds + # to `.call` method). + # + # custom_introspection_response do |token, context| + # { + # "sub": "Z5O3upPC88QrAjx00dis", + # "aud": "https://protected.example.net/resource", + # } + # end + # + # or + # + # custom_introspection_response CustomIntrospectionResponder + # Specify what grant flows are enabled in array of Strings. The valid # strings and the flows they enable are: # diff --git a/spec/controllers/tokens_controller_spec.rb b/spec/controllers/tokens_controller_spec.rb index b7c2392a1..6fdf239ef 100644 --- a/spec/controllers/tokens_controller_spec.rb +++ b/spec/controllers/tokens_controller_spec.rb @@ -159,6 +159,33 @@ end end + context 'using custom introspection response' do + let(:client) { FactoryBot.create(:application) } + let(:access_token) { FactoryBot.create(:access_token, application: client) } + + before do + Doorkeeper.configure do + orm DOORKEEPER_ORM + custom_introspection_response do |_token, _context| + { + sub: 'Z5O3upPC88QrAjx00dis', + aud: 'https://protected.example.net/resource' + } + end + end + end + + it 'responds with full token introspection' do + request.headers['Authorization'] = "Bearer #{access_token.token}" + + post :introspect, params: { token: access_token.token } + + expect(json_response).to include('client_id', 'token_type', 'exp', 'iat', 'sub', 'aud') + should_have_json 'sub', 'Z5O3upPC88QrAjx00dis' + should_have_json 'aud', 'https://protected.example.net/resource' + end + end + context 'public access token' do let(:client) { FactoryBot.create(:application) } let(:access_token) { FactoryBot.create(:access_token, application: nil) }