FIX: Improve email validation error handling for external logins (#11307)
- Display reason for validation error when logging in via an authenticator - Fix email validation handling for 'Discourse SSO', and add a spec Previously, validation errors (e.g. blocked or already-taken emails) would raise a generic error with no useful information.
This commit is contained in:
parent
4638c6fc8d
commit
20c0da8516
|
@ -244,7 +244,7 @@ class SessionController < ApplicationController
|
||||||
text = nil
|
text = nil
|
||||||
|
|
||||||
# If there's a problem with the email we can explain that
|
# If there's a problem with the email we can explain that
|
||||||
if (e.record.is_a?(User) && e.record.errors[:email].present?)
|
if (e.record.is_a?(User) && e.record.errors[:primary_email].present?)
|
||||||
if e.record.email.blank?
|
if e.record.email.blank?
|
||||||
text = I18n.t("sso.no_email")
|
text = I18n.t("sso.no_email")
|
||||||
else
|
else
|
||||||
|
|
|
@ -67,20 +67,20 @@ class Users::OmniauthCallbacksController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
@auth_result.destination_url = @origin
|
@auth_result.destination_url = @origin
|
||||||
|
@auth_result.authenticator_name = authenticator.name
|
||||||
|
|
||||||
if @auth_result.failed?
|
return render_auth_result_failure if @auth_result.failed?
|
||||||
flash[:error] = @auth_result.failed_reason.html_safe
|
|
||||||
render('failure')
|
complete_response_data
|
||||||
else
|
|
||||||
@auth_result.authenticator_name = authenticator.name
|
return render_auth_result_failure if @auth_result.failed?
|
||||||
complete_response_data
|
|
||||||
cookies['_bypass_cache'] = true
|
cookies['_bypass_cache'] = true
|
||||||
cookies[:authentication_data] = {
|
cookies[:authentication_data] = {
|
||||||
value: @auth_result.to_client_hash.to_json,
|
value: @auth_result.to_client_hash.to_json,
|
||||||
path: Discourse.base_path("/")
|
path: Discourse.base_path("/")
|
||||||
}
|
}
|
||||||
redirect_to @origin
|
redirect_to @origin
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def failure
|
def failure
|
||||||
|
@ -98,6 +98,11 @@ class Users::OmniauthCallbacksController < ApplicationController
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
def render_auth_result_failure
|
||||||
|
flash[:error] = @auth_result.failed_reason.html_safe
|
||||||
|
render 'failure'
|
||||||
|
end
|
||||||
|
|
||||||
def complete_response_data
|
def complete_response_data
|
||||||
if @auth_result.user
|
if @auth_result.user
|
||||||
user_found(@auth_result.user)
|
user_found(@auth_result.user)
|
||||||
|
@ -138,7 +143,14 @@ class Users::OmniauthCallbacksController < ApplicationController
|
||||||
elsif ScreenedIpAddress.block_admin_login?(user, request.remote_ip)
|
elsif ScreenedIpAddress.block_admin_login?(user, request.remote_ip)
|
||||||
@auth_result.admin_not_allowed_from_ip_address = true
|
@auth_result.admin_not_allowed_from_ip_address = true
|
||||||
elsif Guardian.new(user).can_access_forum? && user.active # log on any account that is active with forum access
|
elsif Guardian.new(user).can_access_forum? && user.active # log on any account that is active with forum access
|
||||||
user.save! if @auth_result.apply_user_attributes!
|
begin
|
||||||
|
user.save! if @auth_result.apply_user_attributes!
|
||||||
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
|
@auth_result.failed = true
|
||||||
|
@auth_result.failed_reason = e.record.errors.full_messages.join(", ")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
log_on_user(user)
|
log_on_user(user)
|
||||||
Invite.invalidate_for_email(user.email) # invite link can't be used to log in anymore
|
Invite.invalidate_for_email(user.email) # invite link can't be used to log in anymore
|
||||||
session[:authentication] = nil # don't carry around old auth info, perhaps move elsewhere
|
session[:authentication] = nil # don't carry around old auth info, perhaps move elsewhere
|
||||||
|
|
|
@ -387,6 +387,25 @@ RSpec.describe Users::OmniauthCallbacksController do
|
||||||
expect(user.email).to eq('email@example.com')
|
expect(user.email).to eq('email@example.com')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "shows error when sso_overrides_email causes a validation error" do
|
||||||
|
SiteSetting.email_editable = false
|
||||||
|
SiteSetting.sso_overrides_email = true
|
||||||
|
|
||||||
|
UserAssociatedAccount.create!(provider_name: "google_oauth2", user_id: user.id, provider_uid: '123545')
|
||||||
|
|
||||||
|
google_email = user.email
|
||||||
|
user.update!(email: 'anotheremail@example.com')
|
||||||
|
Fabricate(:user, email: google_email) # Another user has the google account email
|
||||||
|
|
||||||
|
get "/auth/google_oauth2/callback"
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.body).to include(I18n.t("errors.messages.taken"))
|
||||||
|
expect(session[:current_user_id]).to eq(nil)
|
||||||
|
|
||||||
|
user.reload
|
||||||
|
expect(user.email).to eq('anotheremail@example.com')
|
||||||
|
end
|
||||||
|
|
||||||
context 'when user has TOTP enabled' do
|
context 'when user has TOTP enabled' do
|
||||||
before do
|
before do
|
||||||
user.create_totp(enabled: true)
|
user.create_totp(enabled: true)
|
||||||
|
|
|
@ -580,6 +580,22 @@ RSpec.describe SessionController do
|
||||||
expect(response.body).to include(I18n.t('sso.blank_id_error'))
|
expect(response.body).to include(I18n.t('sso.blank_id_error'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'can handle invalid sso email validation errors' do
|
||||||
|
SiteSetting.blocked_email_domains = "test.com"
|
||||||
|
sso = get_sso("/")
|
||||||
|
sso.email = "test@test.com"
|
||||||
|
sso.external_id = '123'
|
||||||
|
sso.username = 'sam'
|
||||||
|
|
||||||
|
messages = track_log_messages(level: Logger::WARN) do
|
||||||
|
get "/session/sso_login", params: Rack::Utils.parse_query(sso.payload), headers: headers
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(messages.length).to eq(0)
|
||||||
|
expect(response.status).to eq(500)
|
||||||
|
expect(response.body).to include(I18n.t("sso.email_error", email: ERB::Util.html_escape("test@test.com")))
|
||||||
|
end
|
||||||
|
|
||||||
it 'can handle invalid sso external ids due to banned word' do
|
it 'can handle invalid sso external ids due to banned word' do
|
||||||
sso = get_sso("/")
|
sso = get_sso("/")
|
||||||
sso.email = "test@test.com"
|
sso.email = "test@test.com"
|
||||||
|
|
Loading…
Reference in New Issue