FEATURE: Allow specifiying required paths when retrieving userinfo (#96)

When retrieving userinfo with oauth2_fetch_user_details=true, we sometimes want to disallow account creation if an attribute is not fulfilled.

This commit adds a new register oauth2_basic_required_json_path which will kick in when retrieving userinfo.
This commit is contained in:
Natalie Tay 2024-01-31 20:19:18 +08:00 committed by GitHub
parent d1161b99a7
commit 895db120e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 0 deletions

View File

@ -78,6 +78,18 @@ end
# 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
# After authentication, we'll use this to confirm that the registered json paths are fulfilled, or display an error.
# This requires SiteSetting.oauth2_fetch_user_details? to be true, and can be used with
# DiscoursePluginRegistry.oauth2_basic_additional_json_paths.
#
# Example usage:
# DiscoursePluginRegistry.register_oauth2_basic_required_json_path({
# path: "extra:data.is_allowed_user",
# required_value: true,
# error_message: I18n.t("auth.user_not_allowed")
# }, self)
DiscoursePluginRegistry.define_filtered_register :oauth2_basic_required_json_paths
class ::OAuth2BasicAuthenticator < Auth::ManagedAuthenticator
def name
"oauth2_basic"
@ -312,6 +324,15 @@ class ::OAuth2BasicAuthenticator < Auth::ManagedAuthenticator
DiscoursePluginRegistry.oauth2_basic_additional_json_paths.each do |detail|
auth["extra"][detail] = fetched_user_details["extra:#{detail}"]
end
DiscoursePluginRegistry.oauth2_basic_required_json_paths.each do |x|
if fetched_user_details[x[:path]] != x[:required_value]
result = Auth::Result.new
result.failed = true
result.failed_reason = x[:error_message]
return result
end
end
else
result = Auth::Result.new
result.failed = true

View File

@ -124,6 +124,54 @@ describe OAuth2BasicAuthenticator do
expect(associated_account.extra[custom_path]).to eq("received")
end
end
describe "required attributes" do
after { DiscoursePluginRegistry.reset_register!(:oauth2_basic_required_json_paths) }
it "'authenticates' successfully if required json path is fulfilled" do
DiscoursePluginRegistry.register_oauth2_basic_additional_json_path(
"account.is_legit",
Plugin::Instance.new,
)
DiscoursePluginRegistry.register_oauth2_basic_required_json_path(
{ path: "extra:account.is_legit", required_value: true },
Plugin::Instance.new,
)
response = {
status: 200,
body: '{"account":{"email":"newemail@example.com","is_legit":true}}',
}
stub_request(:get, SiteSetting.oauth2_user_json_url).to_return(response)
result = authenticator.after_authenticate(auth)
expect(result.failed).to eq(false)
end
it "fails 'authentication' if required json path is unfulfilled" do
DiscoursePluginRegistry.register_oauth2_basic_additional_json_path(
"account.is_legit",
Plugin::Instance.new,
)
DiscoursePluginRegistry.register_oauth2_basic_required_json_path(
{
path: "extra:account.is_legit",
required_value: true,
error_message: "You're not legit",
},
Plugin::Instance.new,
)
response = {
status: 200,
body: '{"account":{"email":"newemail@example.com","is_legit":false}}',
}
stub_request(:get, SiteSetting.oauth2_user_json_url).to_return(response)
result = authenticator.after_authenticate(auth)
expect(result.failed).to eq(true)
expect(result.failed_reason).to eq("You're not legit")
end
end
end
describe "avatar downloading" do