FEATURE: Fetch custom attributes from the user details. (#47)

Other plugins can tell the authenticator to traverse the user details JSON using custom paths and store the values in the user associated account extra field.
This commit is contained in:
Roman Rizzi 2021-07-01 18:23:27 -03:00 committed by GitHub
parent 6ee31f6b02
commit d1a912ebc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 2 deletions

View File

@ -71,6 +71,10 @@ class OAuth2FaradayFormatter < Faraday::Logging::Formatter
end end
end end
# You should use this register if you want to add custom paths to traverse the user details JSON.
# We'll store the value in the user associated account's extra attribute hash using the full path as the key.
DiscoursePluginRegistry.define_filtered_register :oauth2_basic_additional_json_paths
class ::OAuth2BasicAuthenticator < Auth::ManagedAuthenticator class ::OAuth2BasicAuthenticator < Auth::ManagedAuthenticator
def name def name
'oauth2_basic' 'oauth2_basic'
@ -164,8 +168,8 @@ class ::OAuth2BasicAuthenticator < Auth::ManagedAuthenticator
end end
end end
def json_walk(result, user_json, prop) def json_walk(result, user_json, prop, custom_path: nil)
path = SiteSetting.public_send("oauth2_json_#{prop}_path") path = custom_path || SiteSetting.public_send("oauth2_json_#{prop}_path")
if path.present? if path.present?
#this.[].that is the same as this.that, allows for both this[0].that and this.[0].that path styles #this.[].that is the same as this.that, allows for both this[0].that and this.[0].that path styles
path = path.gsub(".[].", ".").gsub(".[", "[") path = path.gsub(".[].", ".").gsub(".[", "[")
@ -229,6 +233,11 @@ class ::OAuth2BasicAuthenticator < Auth::ManagedAuthenticator
json_walk(result, user_json, :email) json_walk(result, user_json, :email)
json_walk(result, user_json, :email_verified) json_walk(result, user_json, :email_verified)
json_walk(result, user_json, :avatar) json_walk(result, user_json, :avatar)
DiscoursePluginRegistry.oauth2_basic_additional_json_paths.each do |detail|
prop = "extra:#{detail}"
json_walk(result, user_json, prop, custom_path: detail)
end
end end
result result
else else
@ -259,6 +268,10 @@ class ::OAuth2BasicAuthenticator < Auth::ManagedAuthenticator
['name', 'email', 'email_verified'].each do |property| ['name', 'email', 'email_verified'].each do |property|
auth['info'][property] = fetched_user_details[property.to_sym] if fetched_user_details[property.to_sym] auth['info'][property] = fetched_user_details[property.to_sym] if fetched_user_details[property.to_sym]
end end
DiscoursePluginRegistry.oauth2_basic_additional_json_paths.each do |detail|
auth['extra'][detail] = fetched_user_details["extra:#{detail}"]
end
else else
result = Auth::Result.new result = Auth::Result.new
result.failed = true result.failed = true

View File

@ -122,6 +122,31 @@ describe OAuth2BasicAuthenticator do
result = authenticator.after_authenticate(auth) result = authenticator.after_authenticate(auth)
expect(result.failed).to eq(true) expect(result.failed).to eq(true)
end end
describe 'fetch custom attributes' do
after { DiscoursePluginRegistry.reset! }
let(:response) do
{
status: 200,
body: '{"account":{"email":"newemail@example.com","custom_attr":"received"}}'
}
end
it 'stores custom attributes in the user associated account' do
custom_path = 'account.custom_attr'
DiscoursePluginRegistry.register_oauth2_basic_additional_json_path(
custom_path,
Plugin::Instance.new
)
stub_request(:get, SiteSetting.oauth2_user_json_url).to_return(response)
result = authenticator.after_authenticate(auth)
associated_account = UserAssociatedAccount.last
expect(associated_account.extra[custom_path]).to eq("received")
end
end
end end
context 'avatar downloading' do context 'avatar downloading' do