OpenProject is the leading open source project management software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openproject/app/controllers/concerns/omniauth_login.rb

153 lines
4.8 KiB

require 'uri'
##
# Intended to be used by the AccountController to handle omniauth logins
module Concerns::OmniauthLogin
def self.included(base)
# disable CSRF protection since that should be covered by the omniauth strategy
base.skip_before_filter :verify_authenticity_token, :only => [:omniauth_login]
end
def omniauth_login
auth_hash = request.env['omniauth.auth']
return render_400 unless auth_hash.valid?
# Set back url to page the omniauth login link was clicked on
params[:back_url] = request.env['omniauth.origin']
user = User.find_or_initialize_by_identity_url identity_url_from_omniauth(auth_hash)
decision = OpenProject::OmniAuth::Authorization.authorized? auth_hash
if decision.approve?
authorization_successful user, auth_hash
else
authorization_failed user, decision.message
end
end
def omniauth_failure
logger.warn(params[:message]) if params[:message]
show_error I18n.t(:error_external_authentication_failed)
end
def self.direct_login?
direct_login_provider.is_a? String
end
##
# Per default the user may choose the usual password login as well as several omniauth providers
# on the login page and in the login drop down menu.
#
# With his configuration option you can set a specific omniauth provider to be
# used for direct login. Meaning that the login provider selection is skipped and
# the configured provider is used directly instead.
#
# If this option is active /login will lead directly to the configured omniauth provider
# and so will a click on 'Sign in' (as opposed to opening the drop down menu).
def self.direct_login_provider
OpenProject::Configuration['omniauth_direct_login_provider']
end
def self.direct_login_provider_url(params = {})
url_with_params "/auth/#{direct_login_provider}", params if direct_login?
end
private
def authorization_successful(user, auth_hash)
if user.new_record?
create_user_from_omniauth user, auth_hash
else
if user.active?
user.log_successful_login
OpenProject::OmniAuth::Authorization.after_login! user, auth_hash
end
login_user_if_active(user)
end
end
def authorization_failed(user, error)
logger.warn "Authorization for User #{user.id} failed: #{error}"
show_error error
end
def show_error(error)
flash[:error] = error
redirect_to :action => 'login'
end
# a user may login via omniauth and (if that user does not exist
# in our database) will be created using this method.
def create_user_from_omniauth(user, auth_hash)
# Self-registration off
return self_registration_disabled unless Setting.self_registration?
fill_user_fields_from_omniauth user, auth_hash
opts = { after_login: ->(u) { OpenProject::OmniAuth::Authorization.after_login! u, auth_hash } }
# Create on the fly
register_user_according_to_setting(user, opts) do
# Allow registration form to show provider-specific title
@omniauth_strategy = auth_hash[:provider]
# Store a timestamp so we can later make sure that authentication information can
# only be reused for a short time.
session_info = auth_hash.merge(omniauth: true, timestamp: Time.new)
onthefly_creation_failed(user, session_info)
end
end
def register_via_omniauth(user, session, permitted_params)
auth = session[:auth_source_registration]
return if handle_omniauth_registration_expired(auth)
fill_user_fields_from_omniauth(user, auth)
user.update_attributes(permitted_params.user_register_via_omniauth)
opts = { after_login: ->(u) { OpenProject::OmniAuth::Authorization.after_login! u, auth } }
register_user_according_to_setting user, opts
end
def fill_user_fields_from_omniauth(user, auth)
user.update_attributes omniauth_hash_to_user_attributes(auth)
user.register
user
end
def omniauth_hash_to_user_attributes(auth)
info = auth[:info]
{
login: info[:email],
mail: info[:email],
firstname: info[:first_name] || info[:name],
lastname: info[:last_name],
identity_url: identity_url_from_omniauth(auth)
}
end
def identity_url_from_omniauth(auth)
"#{auth[:provider]}:#{auth[:uid]}"
end
# if the omni auth registration happened too long ago,
# we don't accept it anymore.
def handle_omniauth_registration_expired(auth)
if auth['timestamp'] < Time.now - 30.minutes
flash[:error] = I18n.t(:error_omniauth_registration_timed_out)
redirect_to(signin_url)
end
end
def self.url_with_params(url, params = {})
URI.parse(url).tap do |uri|
query = URI.decode_www_form(uri.query || '')
params.each do |key, value|
query << [key, value]
end
uri.query = URI.encode_www_form(query) unless query.empty?
end.to_s
end
end