2013-02-12 21:47:22 +08:00
|
|
|
# -*- encoding : utf-8 -*-
|
2019-05-03 06:17:27 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2013-02-12 21:47:22 +08:00
|
|
|
class Users::OmniauthCallbacksController < ApplicationController
|
2013-08-23 14:20:43 +08:00
|
|
|
|
2017-08-31 12:06:56 +08:00
|
|
|
skip_before_action :redirect_to_login_if_required
|
2013-02-12 21:47:22 +08:00
|
|
|
|
2017-11-16 03:04:26 +08:00
|
|
|
layout 'no_ember'
|
2013-02-12 21:47:22 +08:00
|
|
|
|
|
|
|
# need to be able to call this
|
2017-08-31 12:06:56 +08:00
|
|
|
skip_before_action :check_xhr
|
2013-02-12 21:47:22 +08:00
|
|
|
|
2013-07-29 13:13:13 +08:00
|
|
|
# this is the only spot where we allow CSRF, our openid / oauth redirect
|
|
|
|
# will not have a CSRF token, however the payload is all validated so its safe
|
2017-08-31 12:06:56 +08:00
|
|
|
skip_before_action :verify_authenticity_token, only: :complete
|
2013-02-12 21:47:22 +08:00
|
|
|
|
2019-08-08 18:57:28 +08:00
|
|
|
def confirm_request
|
|
|
|
self.class.find_authenticator(params[:provider])
|
2019-08-08 20:57:18 +08:00
|
|
|
render locals: { hide_auth_buttons: true }
|
2019-08-08 18:57:28 +08:00
|
|
|
end
|
|
|
|
|
2013-02-12 21:47:22 +08:00
|
|
|
def complete
|
2013-08-23 14:20:43 +08:00
|
|
|
auth = request.env["omniauth.auth"]
|
2017-05-05 03:35:03 +08:00
|
|
|
raise Discourse::NotFound unless request.env["omniauth.auth"]
|
|
|
|
|
2013-11-20 01:58:12 +08:00
|
|
|
auth[:session] = session
|
2013-08-01 13:59:57 +08:00
|
|
|
|
2013-08-23 14:20:43 +08:00
|
|
|
authenticator = self.class.find_authenticator(params[:provider])
|
2013-03-05 02:44:41 +08:00
|
|
|
|
2018-12-11 21:19:00 +08:00
|
|
|
if session.delete(:auth_reconnect) && authenticator.can_connect_existing_user? && current_user
|
2019-07-17 19:34:02 +08:00
|
|
|
# Save to redis, with a secret token, then redirect to confirmation screen
|
|
|
|
token = SecureRandom.hex
|
2019-12-03 17:05:53 +08:00
|
|
|
Discourse.redis.setex "#{Users::AssociateAccountsController::REDIS_PREFIX}_#{current_user.id}_#{token}", 10.minutes, auth.to_json
|
2020-10-09 19:51:24 +08:00
|
|
|
return redirect_to "#{Discourse.base_path}/associate/#{token}"
|
2018-07-23 23:51:57 +08:00
|
|
|
else
|
2020-11-13 22:41:54 +08:00
|
|
|
DiscourseEvent.trigger(:before_auth, authenticator, auth)
|
2018-07-23 23:51:57 +08:00
|
|
|
@auth_result = authenticator.after_authenticate(auth)
|
2021-03-31 20:40:58 +08:00
|
|
|
@auth_result.user = nil if @auth_result&.user&.staged # Treat staged users the same as unregistered users
|
2019-06-22 02:57:49 +08:00
|
|
|
DiscourseEvent.trigger(:after_auth, authenticator, @auth_result)
|
2018-07-23 23:51:57 +08:00
|
|
|
end
|
2013-08-01 13:59:57 +08:00
|
|
|
|
2019-05-15 16:55:31 +08:00
|
|
|
preferred_origin = request.env['omniauth.origin']
|
2018-01-27 01:52:27 +08:00
|
|
|
|
2021-03-31 17:23:12 +08:00
|
|
|
if session[:destination_url].present?
|
|
|
|
preferred_origin = session[:destination_url]
|
|
|
|
session.delete(:destination_url)
|
|
|
|
elsif SiteSetting.enable_discourse_connect_provider && payload = cookies.delete(:sso_payload)
|
2019-05-15 16:55:31 +08:00
|
|
|
preferred_origin = session_sso_provider_url + "?" + payload
|
2018-10-05 02:31:08 +08:00
|
|
|
elsif cookies[:destination_url].present?
|
2019-05-15 16:55:31 +08:00
|
|
|
preferred_origin = cookies[:destination_url]
|
2016-09-16 11:48:50 +08:00
|
|
|
cookies.delete(:destination_url)
|
|
|
|
end
|
|
|
|
|
2019-05-15 16:55:31 +08:00
|
|
|
if preferred_origin.present?
|
2018-03-28 16:20:08 +08:00
|
|
|
parsed = begin
|
2019-05-15 16:55:31 +08:00
|
|
|
URI.parse(preferred_origin)
|
2018-08-14 18:23:32 +08:00
|
|
|
rescue URI::Error
|
2018-03-28 16:20:08 +08:00
|
|
|
end
|
|
|
|
|
2020-12-04 05:27:55 +08:00
|
|
|
if valid_origin?(parsed)
|
2019-05-03 06:17:27 +08:00
|
|
|
@origin = +"#{parsed.path}"
|
2019-03-19 20:39:13 +08:00
|
|
|
@origin << "?#{parsed.query}" if parsed.query
|
2015-10-13 09:23:34 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-01-27 01:52:27 +08:00
|
|
|
if @origin.blank?
|
2020-10-09 19:51:24 +08:00
|
|
|
@origin = Discourse.base_path("/")
|
2015-10-13 09:23:34 +08:00
|
|
|
end
|
|
|
|
|
2019-05-15 16:55:31 +08:00
|
|
|
@auth_result.destination_url = @origin
|
2020-11-23 19:06:08 +08:00
|
|
|
@auth_result.authenticator_name = authenticator.name
|
2019-03-19 20:39:13 +08:00
|
|
|
|
2020-11-23 19:06:08 +08:00
|
|
|
return render_auth_result_failure if @auth_result.failed?
|
|
|
|
|
|
|
|
complete_response_data
|
|
|
|
|
|
|
|
return render_auth_result_failure if @auth_result.failed?
|
|
|
|
|
|
|
|
cookies['_bypass_cache'] = true
|
|
|
|
cookies[:authentication_data] = {
|
|
|
|
value: @auth_result.to_client_hash.to_json,
|
|
|
|
path: Discourse.base_path("/")
|
|
|
|
}
|
|
|
|
redirect_to @origin
|
2013-02-12 21:47:22 +08:00
|
|
|
end
|
|
|
|
|
2020-12-04 05:27:55 +08:00
|
|
|
def valid_origin?(uri)
|
|
|
|
return false if uri.nil?
|
|
|
|
return false if uri.host.present? && uri.host != Discourse.current_hostname
|
|
|
|
return false if uri.path.start_with?("#{Discourse.base_path}/auth/")
|
|
|
|
return false if uri.path.start_with?("#{Discourse.base_path}/login")
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2013-02-15 03:11:13 +08:00
|
|
|
def failure
|
2019-08-12 17:55:02 +08:00
|
|
|
error_key = params[:message].to_s.gsub(/[^\w-]/, "") || "generic"
|
|
|
|
flash[:error] = I18n.t("login.omniauth_error.#{error_key}", default: I18n.t("login.omniauth_error.generic"))
|
2017-11-16 03:04:26 +08:00
|
|
|
render 'failure'
|
2013-02-15 03:11:13 +08:00
|
|
|
end
|
|
|
|
|
2013-08-23 14:20:43 +08:00
|
|
|
def self.find_authenticator(name)
|
2018-07-23 23:51:57 +08:00
|
|
|
Discourse.enabled_authenticators.each do |authenticator|
|
|
|
|
return authenticator if authenticator.name == name
|
2013-08-18 12:43:59 +08:00
|
|
|
end
|
2018-07-23 23:51:57 +08:00
|
|
|
raise Discourse::InvalidAccess.new(I18n.t('authenticator_not_found'))
|
2013-02-12 21:47:22 +08:00
|
|
|
end
|
|
|
|
|
2013-08-23 14:20:43 +08:00
|
|
|
protected
|
2013-02-26 12:28:32 +08:00
|
|
|
|
2020-11-23 19:06:08 +08:00
|
|
|
def render_auth_result_failure
|
|
|
|
flash[:error] = @auth_result.failed_reason.html_safe
|
|
|
|
render 'failure'
|
|
|
|
end
|
|
|
|
|
2014-10-01 00:24:22 +08:00
|
|
|
def complete_response_data
|
2015-06-25 00:12:43 +08:00
|
|
|
if @auth_result.user
|
|
|
|
user_found(@auth_result.user)
|
2020-12-04 05:27:55 +08:00
|
|
|
elsif invite_required?
|
2015-06-25 00:12:43 +08:00
|
|
|
@auth_result.requires_invite = true
|
2014-10-01 00:24:22 +08:00
|
|
|
else
|
2015-06-25 00:12:43 +08:00
|
|
|
session[:authentication] = @auth_result.session_data
|
2014-10-01 00:24:22 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-12-04 05:27:55 +08:00
|
|
|
def invite_required?
|
2021-03-02 15:13:04 +08:00
|
|
|
if SiteSetting.invite_only?
|
|
|
|
path = Discourse.route_for(@origin)
|
|
|
|
return true unless path
|
|
|
|
return true if path[:controller] != "invites" && path[:action] != "show"
|
|
|
|
!Invite.exists?(invite_key: path[:id])
|
|
|
|
end
|
2020-12-04 05:27:55 +08:00
|
|
|
end
|
|
|
|
|
2013-08-23 14:20:43 +08:00
|
|
|
def user_found(user)
|
2020-01-15 18:27:12 +08:00
|
|
|
if user.has_any_second_factor_methods_enabled?
|
2018-03-01 15:47:07 +08:00
|
|
|
@auth_result.omniauth_disallow_totp = true
|
2018-05-30 12:14:04 +08:00
|
|
|
@auth_result.email = user.email
|
2018-03-01 15:47:07 +08:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2021-03-31 20:40:58 +08:00
|
|
|
# automatically activate any account if a provider marked the email valid
|
2017-03-01 11:58:24 +08:00
|
|
|
if @auth_result.email_valid && @auth_result.email == user.email
|
2019-08-28 19:49:11 +08:00
|
|
|
if !user.active || !user.email_confirmed?
|
|
|
|
user.update!(password: SecureRandom.hex)
|
2019-08-28 21:43:25 +08:00
|
|
|
|
|
|
|
# Ensure there is an active email token
|
|
|
|
unless EmailToken.where(email: user.email, confirmed: true).exists? ||
|
|
|
|
user.email_tokens.active.where(email: user.email).exists?
|
|
|
|
user.email_tokens.create!(email: user.email)
|
|
|
|
end
|
|
|
|
|
2019-08-28 19:49:11 +08:00
|
|
|
user.activate
|
|
|
|
end
|
2017-12-12 20:08:57 +08:00
|
|
|
user.update!(registration_ip_address: request.remote_ip) if user.registration_ip_address.blank?
|
2013-08-02 10:03:53 +08:00
|
|
|
end
|
|
|
|
|
2015-03-03 01:13:10 +08:00
|
|
|
if ScreenedIpAddress.should_block?(request.remote_ip)
|
2015-06-25 00:12:43 +08:00
|
|
|
@auth_result.not_allowed_from_ip_address = true
|
2015-03-03 01:13:10 +08:00
|
|
|
elsif ScreenedIpAddress.block_admin_login?(user, request.remote_ip)
|
2015-06-25 00:12:43 +08:00
|
|
|
@auth_result.admin_not_allowed_from_ip_address = true
|
2014-09-05 06:50:27 +08:00
|
|
|
elsif Guardian.new(user).can_access_forum? && user.active # log on any account that is active with forum access
|
2020-11-23 19:06:08 +08:00
|
|
|
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
|
|
|
|
|
2013-08-23 14:20:43 +08:00
|
|
|
log_on_user(user)
|
2014-01-22 05:53:46 +08:00
|
|
|
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
|
2015-06-25 00:12:43 +08:00
|
|
|
@auth_result.authenticated = true
|
2013-03-01 23:23:21 +08:00
|
|
|
else
|
2013-08-28 15:18:31 +08:00
|
|
|
if SiteSetting.must_approve_users? && !user.approved?
|
2015-06-25 00:12:43 +08:00
|
|
|
@auth_result.awaiting_approval = true
|
2013-07-11 14:02:18 +08:00
|
|
|
else
|
2015-06-25 00:12:43 +08:00
|
|
|
@auth_result.awaiting_activation = true
|
2013-07-11 14:02:18 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-12 21:47:22 +08:00
|
|
|
end
|