discourse/app/controllers/users/omniauth_callbacks_controller.rb
Guo Xiang Tan 142571bba0 Remove use of rescue nil.
* `rescue nil` is a really bad pattern to use in our code base.
  We should rescue errors that we expect the code to throw and
  not rescue everything because we're unsure of what errors the
  code would throw. This would reduce the amount of pain we face
  when debugging why something isn't working as expexted. I've
  been bitten countless of times by errors being swallowed as a
  result during debugging sessions.
2018-04-02 13:52:51 +08:00

160 lines
4.7 KiB
Ruby

# -*- encoding : utf-8 -*-
require_dependency 'email'
require_dependency 'enum'
require_dependency 'user_name_suggester'
class Users::OmniauthCallbacksController < ApplicationController
BUILTIN_AUTH = [
Auth::FacebookAuthenticator.new,
Auth::GoogleOAuth2Authenticator.new,
Auth::OpenIdAuthenticator.new("yahoo", "https://me.yahoo.com", trusted: true),
Auth::GithubAuthenticator.new,
Auth::TwitterAuthenticator.new,
Auth::InstagramAuthenticator.new
]
skip_before_action :redirect_to_login_if_required
layout 'no_ember'
def self.types
@types ||= Enum.new(:facebook, :instagram, :twitter, :google, :yahoo, :github, :persona, :cas)
end
# need to be able to call this
skip_before_action :check_xhr
# 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
skip_before_action :verify_authenticity_token, only: :complete
def complete
auth = request.env["omniauth.auth"]
raise Discourse::NotFound unless request.env["omniauth.auth"]
auth[:session] = session
authenticator = self.class.find_authenticator(params[:provider])
provider = Discourse.auth_providers && Discourse.auth_providers.find { |p| p.name == params[:provider] }
@auth_result = authenticator.after_authenticate(auth)
origin = request.env['omniauth.origin']
if cookies[:destination_url].present?
origin = cookies[:destination_url]
cookies.delete(:destination_url)
end
if origin.present?
parsed = begin
URI.parse(origin)
rescue URI::InvalidURIError
end
if parsed
@origin = "#{parsed.path}?#{parsed.query}"
end
end
if @origin.blank?
@origin = Discourse.base_uri("/")
else
@auth_result.destination_url = origin
end
if @auth_result.failed?
flash[:error] = @auth_result.failed_reason.html_safe
return render('failure')
else
@auth_result.authenticator_name = authenticator.name
complete_response_data
if (provider && provider.full_screen_login) || cookies['fsl']
cookies.delete('fsl')
cookies['_bypass_cache'] = true
flash[:authentication_data] = @auth_result.to_client_hash.to_json
redirect_to @origin
else
respond_to do |format|
format.html
format.json { render json: @auth_result.to_client_hash }
end
end
end
end
def failure
flash[:error] = I18n.t("login.omniauth_error")
render 'failure'
end
def self.find_authenticator(name)
BUILTIN_AUTH.each do |authenticator|
if authenticator.name == name
raise Discourse::InvalidAccess.new("provider is not enabled") unless SiteSetting.send("enable_#{name}_logins?")
return authenticator
end
end
Discourse.auth_providers.each do |provider|
return provider.authenticator if provider.name == name
end
raise Discourse::InvalidAccess.new("provider is not found")
end
protected
def complete_response_data
if @auth_result.user
user_found(@auth_result.user)
elsif SiteSetting.invite_only?
@auth_result.requires_invite = true
else
session[:authentication] = @auth_result.session_data
end
end
def user_found(user)
if user.totp_enabled?
@auth_result.omniauth_disallow_totp = true
return
end
# automatically activate/unstage any account if a provider marked the email valid
if @auth_result.email_valid && @auth_result.email == user.email
user.update!(staged: false)
# 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
user.activate
user.update!(registration_ip_address: request.remote_ip) if user.registration_ip_address.blank?
end
if ScreenedIpAddress.should_block?(request.remote_ip)
@auth_result.not_allowed_from_ip_address = true
elsif ScreenedIpAddress.block_admin_login?(user, request.remote_ip)
@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
log_on_user(user)
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
@auth_result.authenticated = true
else
if SiteSetting.must_approve_users? && !user.approved?
@auth_result.awaiting_approval = true
else
@auth_result.awaiting_activation = true
end
end
end
end