2011-02-01 09:57:29 +08:00
|
|
|
#
|
2013-08-22 00:50:34 +08:00
|
|
|
# Copyright (C) 2011 - 2013 Instructure, Inc.
|
2011-02-01 09:57:29 +08:00
|
|
|
#
|
|
|
|
# This file is part of Canvas.
|
|
|
|
#
|
|
|
|
# Canvas is free software: you can redistribute it and/or modify it under
|
|
|
|
# the terms of the GNU Affero General Public License as published by the Free
|
|
|
|
# Software Foundation, version 3 of the License.
|
|
|
|
#
|
|
|
|
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
|
|
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
|
|
# details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License along
|
|
|
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
|
|
|
|
module AuthenticationMethods
|
2012-08-15 04:24:39 +08:00
|
|
|
|
2011-02-01 09:57:29 +08:00
|
|
|
def authorized(*groups)
|
|
|
|
authorized_roles = groups
|
|
|
|
return true
|
|
|
|
end
|
2012-08-15 04:24:39 +08:00
|
|
|
|
2011-02-01 09:57:29 +08:00
|
|
|
def authorized_roles
|
|
|
|
@authorized_roles ||= []
|
|
|
|
end
|
2012-08-15 04:24:39 +08:00
|
|
|
|
2011-02-01 09:57:29 +08:00
|
|
|
def consume_authorized_roles
|
|
|
|
authorized_roles = []
|
|
|
|
end
|
2012-08-15 04:24:39 +08:00
|
|
|
|
2011-03-08 05:02:56 +08:00
|
|
|
def load_pseudonym_from_policy
|
2013-06-01 00:44:29 +08:00
|
|
|
if (policy_encoded = params['Policy']) &&
|
2011-03-08 05:02:56 +08:00
|
|
|
(signature = params['Signature']) &&
|
2014-06-24 00:38:51 +08:00
|
|
|
signature == Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), Attachment.shared_secret, policy_encoded)).gsub(/\n/, '') &&
|
2011-03-08 05:02:56 +08:00
|
|
|
(policy = JSON.parse(Base64.decode64(policy_encoded)) rescue nil) &&
|
|
|
|
policy['conditions'] &&
|
|
|
|
(credential = policy['conditions'].detect{ |cond| cond.is_a?(Hash) && cond.has_key?("pseudonym_id") })
|
|
|
|
@policy_pseudonym_id = credential['pseudonym_id']
|
|
|
|
# so that we don't have to explicitly skip verify_authenticity_token
|
|
|
|
params[self.class.request_forgery_protection_token] ||= form_authenticity_token
|
|
|
|
end
|
|
|
|
yield if block_given?
|
|
|
|
end
|
|
|
|
|
2011-12-23 04:26:05 +08:00
|
|
|
class AccessTokenError < Exception
|
|
|
|
end
|
|
|
|
|
2014-08-06 01:23:33 +08:00
|
|
|
class LoggedOutError < Exception
|
|
|
|
end
|
|
|
|
|
2013-08-14 06:45:58 +08:00
|
|
|
def self.access_token(request, params_method = :params)
|
2014-07-24 01:14:22 +08:00
|
|
|
auth_header = request.authorization
|
2013-08-14 06:45:58 +08:00
|
|
|
if auth_header.present? && (header_parts = auth_header.split(' ', 2)) && header_parts[0] == 'Bearer'
|
2011-12-23 04:26:05 +08:00
|
|
|
header_parts[1]
|
2013-08-14 06:45:58 +08:00
|
|
|
else
|
|
|
|
request.send(params_method)['access_token'].presence
|
2011-12-23 04:26:05 +08:00
|
|
|
end
|
2013-08-14 06:45:58 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.user_id(request)
|
|
|
|
request.session[:user_id]
|
|
|
|
end
|
|
|
|
|
|
|
|
def load_pseudonym_from_access_token
|
|
|
|
return unless api_request? || params[:action] == 'oauth2_logout'
|
|
|
|
|
|
|
|
token_string = AuthenticationMethods.access_token(request)
|
2011-12-23 04:26:05 +08:00
|
|
|
|
|
|
|
if token_string
|
2012-10-18 04:04:22 +08:00
|
|
|
@access_token = AccessToken.authenticate(token_string)
|
|
|
|
if !@access_token
|
2011-12-23 04:26:05 +08:00
|
|
|
raise AccessTokenError
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
2011-07-28 06:43:25 +08:00
|
|
|
@current_user = @access_token.user
|
2012-01-14 06:58:17 +08:00
|
|
|
@current_pseudonym = @current_user.find_pseudonym_for_account(@domain_root_account, true)
|
2011-12-22 02:59:05 +08:00
|
|
|
unless @current_user && @current_pseudonym
|
2011-12-23 04:26:05 +08:00
|
|
|
raise AccessTokenError
|
2011-07-28 06:43:25 +08:00
|
|
|
end
|
|
|
|
@access_token.used!
|
2011-07-20 01:47:59 +08:00
|
|
|
end
|
2011-12-23 04:26:05 +08:00
|
|
|
end
|
|
|
|
|
2014-11-15 00:45:04 +08:00
|
|
|
def masked_authenticity_token
|
|
|
|
session_options = CanvasRails::Application.config.session_options
|
|
|
|
options = session_options.slice(:domain, :secure)
|
|
|
|
options[:httponly] = HostUrl.is_file_host?(request.host_with_port)
|
|
|
|
CanvasBreachMitigation::MaskingSecrets.masked_authenticity_token(cookies, options)
|
|
|
|
end
|
|
|
|
private :masked_authenticity_token
|
|
|
|
|
2011-12-23 04:26:05 +08:00
|
|
|
def load_user
|
|
|
|
@current_user = @current_pseudonym = nil
|
2014-11-15 00:45:04 +08:00
|
|
|
|
|
|
|
masked_authenticity_token # ensure that the cookie is set
|
2011-12-23 04:26:05 +08:00
|
|
|
|
2011-12-23 06:11:53 +08:00
|
|
|
load_pseudonym_from_access_token
|
2011-07-20 01:47:59 +08:00
|
|
|
|
2011-12-23 04:26:05 +08:00
|
|
|
if !@current_pseudonym
|
2011-10-04 23:21:15 +08:00
|
|
|
if @policy_pseudonym_id
|
2014-09-18 01:29:06 +08:00
|
|
|
@current_pseudonym = Pseudonym.where(id: @policy_pseudonym_id).first
|
2013-04-26 07:06:20 +08:00
|
|
|
elsif @pseudonym_session = PseudonymSession.find
|
|
|
|
@current_pseudonym = @pseudonym_session.record
|
|
|
|
|
|
|
|
# if the session was created before the last time the user explicitly
|
|
|
|
# logged out (of any session for any of their pseudonyms), invalidate
|
|
|
|
# this session
|
2014-05-08 03:49:12 +08:00
|
|
|
invalid_before = @current_pseudonym.user.last_logged_out
|
|
|
|
# they logged out in the future?!? something's busted; just ignore it -
|
|
|
|
# either my clock is off or whoever set this value's clock is off
|
|
|
|
invalid_before = nil if invalid_before && invalid_before > Time.now.utc
|
|
|
|
if invalid_before &&
|
2013-06-22 06:07:00 +08:00
|
|
|
(session_refreshed_at = request.env['encrypted_cookie_store.session_refreshed_at']) &&
|
|
|
|
session_refreshed_at < invalid_before
|
|
|
|
|
2014-11-25 01:11:13 +08:00
|
|
|
logger.info "Invalidating session: Session created before user logged out."
|
2013-06-22 06:07:00 +08:00
|
|
|
destroy_session
|
|
|
|
@current_pseudonym = nil
|
2014-08-06 01:23:33 +08:00
|
|
|
if api_request? || request.format.json?
|
|
|
|
raise LoggedOutError
|
|
|
|
end
|
2013-04-26 07:06:20 +08:00
|
|
|
end
|
2014-10-07 05:18:11 +08:00
|
|
|
|
2015-02-19 06:14:18 +08:00
|
|
|
if @current_pseudonym &&
|
|
|
|
session[:cas_session] &&
|
|
|
|
@current_pseudonym.cas_ticket_expired?(session[:cas_session]) &&
|
|
|
|
@domain_root_account.cas_authentication?
|
2014-10-07 05:18:11 +08:00
|
|
|
|
2015-02-19 06:14:18 +08:00
|
|
|
logger.info "Invalidating session: CAS ticket expired - #{session[:cas_session]}."
|
|
|
|
destroy_session
|
|
|
|
@current_pseudonym = nil
|
2014-10-07 05:18:11 +08:00
|
|
|
|
2015-02-19 06:14:18 +08:00
|
|
|
raise LoggedOutError if api_request? || request.format.json?
|
2014-10-07 05:18:11 +08:00
|
|
|
|
2015-02-19 06:14:18 +08:00
|
|
|
redirect_to_login
|
|
|
|
end
|
2014-10-07 05:18:11 +08:00
|
|
|
end
|
|
|
|
|
2011-05-27 07:41:43 +08:00
|
|
|
if params[:login_success] == '1' && !@current_pseudonym
|
|
|
|
# they just logged in successfully, but we can't find the pseudonym now?
|
|
|
|
# sounds like somebody hates cookies.
|
|
|
|
return redirect_to(login_url(:needs_cookies => '1'))
|
|
|
|
end
|
|
|
|
@current_user = @current_pseudonym && @current_pseudonym.user
|
2011-07-28 06:43:25 +08:00
|
|
|
|
|
|
|
if api_request?
|
2011-08-10 06:54:59 +08:00
|
|
|
# only allow api_key to be used if basic auth was sent, not if they're
|
|
|
|
# just using an app session
|
2011-12-23 04:26:05 +08:00
|
|
|
# this basic auth support is deprecated and marked for removal in 2012
|
2012-03-20 06:24:27 +08:00
|
|
|
if @pseudonym_session.try(:used_basic_auth?) && params[:api_key].present?
|
2014-09-18 01:29:06 +08:00
|
|
|
Shard.birth.activate { @developer_key = DeveloperKey.where(api_key: params[:api_key]).first }
|
2012-03-20 06:24:27 +08:00
|
|
|
end
|
2013-08-22 00:50:34 +08:00
|
|
|
@developer_key ||
|
|
|
|
request.get? ||
|
|
|
|
!allow_forgery_protection ||
|
2014-09-03 02:59:49 +08:00
|
|
|
CanvasBreachMitigation::MaskingSecrets.valid_authenticity_token?(session, cookies, form_authenticity_param) ||
|
|
|
|
CanvasBreachMitigation::MaskingSecrets.valid_authenticity_token?(session, cookies, request.headers['X-CSRF-Token']) ||
|
2013-08-22 00:50:34 +08:00
|
|
|
raise(AccessTokenError)
|
2011-07-28 06:43:25 +08:00
|
|
|
end
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
2011-07-20 01:47:59 +08:00
|
|
|
|
2011-02-01 09:57:29 +08:00
|
|
|
if @current_user && @current_user.unavailable?
|
|
|
|
@current_pseudonym = nil
|
2011-12-23 04:26:05 +08:00
|
|
|
@current_user = nil
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
|
2013-08-14 06:45:58 +08:00
|
|
|
# required by the user throttling middleware
|
|
|
|
session[:user_id] = @current_user.global_id if @current_user
|
|
|
|
|
2011-07-09 02:59:34 +08:00
|
|
|
if @current_user && %w(become_user_id me become_teacher become_student).any? { |k| params.key?(k) }
|
|
|
|
request_become_user = nil
|
2011-02-01 09:57:29 +08:00
|
|
|
if params[:become_user_id]
|
2014-09-18 01:29:06 +08:00
|
|
|
request_become_user = User.where(id: params[:become_user_id]).first
|
2011-02-01 09:57:29 +08:00
|
|
|
elsif params.keys.include?('me')
|
2011-07-09 02:59:34 +08:00
|
|
|
request_become_user = @current_user
|
2011-02-01 09:57:29 +08:00
|
|
|
elsif params.keys.include?('become_teacher')
|
|
|
|
course = Course.find(params[:course_id] || params[:id]) rescue nil
|
|
|
|
teacher = course.teachers.first if course
|
|
|
|
if teacher
|
2011-07-09 02:59:34 +08:00
|
|
|
request_become_user = teacher
|
2011-02-01 09:57:29 +08:00
|
|
|
else
|
2011-05-07 02:44:34 +08:00
|
|
|
flash[:error] = I18n.t('lib.auth.errors.teacher_not_found', "No teacher found")
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
elsif params.keys.include?('become_student')
|
|
|
|
course = Course.find(params[:course_id] || params[:id]) rescue nil
|
|
|
|
student = course.students.first if course
|
|
|
|
if student
|
2011-07-09 02:59:34 +08:00
|
|
|
request_become_user = student
|
2011-02-01 09:57:29 +08:00
|
|
|
else
|
2011-05-07 02:44:34 +08:00
|
|
|
flash[:error] = I18n.t('lib.auth.errors.student_not_found', "No student found")
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
end
|
2011-07-09 02:59:34 +08:00
|
|
|
|
2012-02-21 06:57:32 +08:00
|
|
|
if request_become_user && request_become_user.id != session[:become_user_id].to_i && request_become_user.can_masquerade?(@current_user, @domain_root_account)
|
2011-05-28 00:15:19 +08:00
|
|
|
params_without_become = params.dup
|
|
|
|
params_without_become.delete_if {|k,v| [ 'become_user_id', 'become_teacher', 'become_student', 'me' ].include? k }
|
|
|
|
params_without_become[:only_path] = true
|
|
|
|
session[:masquerade_return_to] = url_for(params_without_become)
|
2011-07-09 02:59:34 +08:00
|
|
|
return redirect_to user_masquerade_url(request_become_user.id)
|
2011-05-28 00:15:19 +08:00
|
|
|
end
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
|
2012-01-24 02:56:25 +08:00
|
|
|
as_user_id = api_request? && params[:as_user_id].presence
|
2011-10-07 05:24:25 +08:00
|
|
|
as_user_id ||= session[:become_user_id]
|
2011-12-28 00:52:51 +08:00
|
|
|
if as_user_id
|
|
|
|
begin
|
|
|
|
user = api_find(User, as_user_id)
|
|
|
|
rescue ActiveRecord::RecordNotFound
|
|
|
|
end
|
2012-02-21 06:57:32 +08:00
|
|
|
if user && user.can_masquerade?(@current_user, @domain_root_account)
|
2011-10-21 03:28:32 +08:00
|
|
|
@real_current_user = @current_user
|
|
|
|
@current_user = user
|
2012-02-07 08:03:33 +08:00
|
|
|
@real_current_pseudonym = @current_pseudonym
|
|
|
|
@current_pseudonym = @current_user.find_pseudonym_for_account(@domain_root_account, true)
|
2011-10-21 03:28:32 +08:00
|
|
|
logger.warn "#{@real_current_user.name}(#{@real_current_user.id}) impersonating #{@current_user.name} on page #{request.url}"
|
2011-12-28 00:52:51 +08:00
|
|
|
elsif api_request?
|
|
|
|
# fail silently for UI, but not for API
|
|
|
|
render :json => {:errors => "Invalid as_user_id"}, :status => :unauthorized
|
|
|
|
return false
|
2011-10-21 03:28:32 +08:00
|
|
|
end
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
@current_user
|
|
|
|
end
|
|
|
|
private :load_user
|
2011-12-23 04:26:05 +08:00
|
|
|
|
2011-02-01 09:57:29 +08:00
|
|
|
def require_user
|
2013-02-13 04:58:04 +08:00
|
|
|
if @current_user && @current_pseudonym
|
|
|
|
true
|
|
|
|
else
|
2012-03-08 08:32:27 +08:00
|
|
|
redirect_to_login
|
2013-02-13 04:58:04 +08:00
|
|
|
false
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
protected :require_user
|
|
|
|
|
2013-04-12 07:05:16 +08:00
|
|
|
def clean_return_to(url)
|
|
|
|
return nil if url.blank?
|
2014-05-05 23:26:26 +08:00
|
|
|
begin
|
|
|
|
uri = URI.parse(url)
|
|
|
|
rescue URI::InvalidURIError
|
|
|
|
return nil
|
|
|
|
end
|
2013-04-12 07:05:16 +08:00
|
|
|
return nil unless uri.path[0] == ?/
|
|
|
|
return "#{request.protocol}#{request.host_with_port}#{uri.path}#{uri.query && "?#{uri.query}"}#{uri.fragment && "##{uri.fragment}"}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def return_to(url, fallback)
|
|
|
|
url = clean_return_to(url) || clean_return_to(fallback)
|
|
|
|
redirect_to url
|
|
|
|
end
|
|
|
|
|
2011-02-01 09:57:29 +08:00
|
|
|
def store_location(uri=nil, overwrite=true)
|
|
|
|
if overwrite || !session[:return_to]
|
2013-12-10 02:46:21 +08:00
|
|
|
uri ||= request.get? ? request.fullpath : request.referrer
|
2013-04-12 07:05:16 +08:00
|
|
|
session[:return_to] = clean_return_to(uri)
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
protected :store_location
|
|
|
|
|
|
|
|
def redirect_back_or_default(default)
|
|
|
|
redirect_to(session[:return_to] || default)
|
2012-05-09 10:27:16 +08:00
|
|
|
session.delete(:return_to)
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
protected :redirect_back_or_default
|
|
|
|
|
2011-06-30 04:05:59 +08:00
|
|
|
def redirect_to_referrer_or_default(default)
|
|
|
|
redirect_to(:back)
|
|
|
|
rescue ActionController::RedirectBackError
|
|
|
|
redirect_to(default)
|
|
|
|
end
|
|
|
|
|
2012-03-08 08:32:27 +08:00
|
|
|
def redirect_to_login
|
|
|
|
respond_to do |format|
|
2012-08-15 04:24:39 +08:00
|
|
|
format.html {
|
|
|
|
store_location
|
|
|
|
flash[:warning] = I18n.t('lib.auth.errors.not_authenticated', "You must be logged in to access this page") unless request.path == '/'
|
|
|
|
opts = {}
|
|
|
|
opts[:canvas_login] = 1 if params[:canvas_login]
|
|
|
|
redirect_to login_url(opts) # should this have :no_auto => 'true' ?
|
|
|
|
}
|
2013-03-27 00:57:36 +08:00
|
|
|
format.json { render_json_unauthorized }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def render_json_unauthorized
|
|
|
|
add_www_authenticate_header if api_request? && !@current_user
|
|
|
|
if @current_user
|
|
|
|
render :json => {
|
|
|
|
:status => I18n.t('lib.auth.status_unauthorized', 'unauthorized'),
|
integrate the active_model-better_errors gem
refs CNVS-6040
This gem will help us output json error responses in the API using error
codes, since by itself ActiveRecord::Errors just deals in human-readable
i18n'd strings, and doesn't store detailed machine-readable information
on the error.
BetterErrors is mostly compatible, there's a few differences that mean I
had to change some unrelated code:
* errors[field_name] always returns an array, even if there's only one
error on the field. This is an improvement IMO.
* errors is indexed by symbol, not by string
* iterating over the errors object now yields
|attr, error_object| rather than |attr, string_message|
This includes a backport of the gem to rails 2.3.
On rails 3, we just use the vanilla gem.
The error codes aren't yet documented in the API docs, support for doing
that will come in a subsequent commit.
test plan: specs, plus you can hit the one api endpoint i've converted
so far -- account authorization configs. try to create an invalid
config, such as adding both cas and ldap configs to the same account,
and verify the error response formatting
Change-Id: Iaadd843ca9ff3f52c64e0256d82b64595c5559fb
Reviewed-on: https://gerrit.instructure.com/26178
Reviewed-by: Brian Palmer <brianp@instructure.com>
Product-Review: Brian Palmer <brianp@instructure.com>
QA-Review: Brian Palmer <brianp@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
2013-11-09 07:56:31 +08:00
|
|
|
:errors => [{ :message => I18n.t('lib.auth.not_authorized', "user not authorized to perform that action") }]
|
2013-03-27 00:57:36 +08:00
|
|
|
},
|
|
|
|
:status => :unauthorized
|
|
|
|
else
|
|
|
|
render :json => {
|
|
|
|
:status => I18n.t('lib.auth.status_unauthenticated', 'unauthenticated'),
|
integrate the active_model-better_errors gem
refs CNVS-6040
This gem will help us output json error responses in the API using error
codes, since by itself ActiveRecord::Errors just deals in human-readable
i18n'd strings, and doesn't store detailed machine-readable information
on the error.
BetterErrors is mostly compatible, there's a few differences that mean I
had to change some unrelated code:
* errors[field_name] always returns an array, even if there's only one
error on the field. This is an improvement IMO.
* errors is indexed by symbol, not by string
* iterating over the errors object now yields
|attr, error_object| rather than |attr, string_message|
This includes a backport of the gem to rails 2.3.
On rails 3, we just use the vanilla gem.
The error codes aren't yet documented in the API docs, support for doing
that will come in a subsequent commit.
test plan: specs, plus you can hit the one api endpoint i've converted
so far -- account authorization configs. try to create an invalid
config, such as adding both cas and ldap configs to the same account,
and verify the error response formatting
Change-Id: Iaadd843ca9ff3f52c64e0256d82b64595c5559fb
Reviewed-on: https://gerrit.instructure.com/26178
Reviewed-by: Brian Palmer <brianp@instructure.com>
Product-Review: Brian Palmer <brianp@instructure.com>
QA-Review: Brian Palmer <brianp@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
2013-11-09 07:56:31 +08:00
|
|
|
:errors => [{ :message => I18n.t('lib.auth.authentication_required', "user authorization required") }]
|
2013-03-27 00:57:36 +08:00
|
|
|
},
|
|
|
|
:status => :unauthorized
|
2012-03-08 08:32:27 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-03-27 00:57:36 +08:00
|
|
|
def add_www_authenticate_header
|
|
|
|
response['WWW-Authenticate'] = %{Bearer realm="canvas-lms"}
|
|
|
|
end
|
|
|
|
|
2011-02-01 09:57:29 +08:00
|
|
|
# Reset the session, and copy the specified keys over to the new session.
|
|
|
|
# Please consider the security implications of any keys you copy over.
|
|
|
|
def reset_session_saving_keys(*keys)
|
|
|
|
# can't use slice, because session has a different ctor than a normal hash
|
|
|
|
saved = {}
|
2011-11-03 04:59:41 +08:00
|
|
|
keys.each { |k| saved[k] = session[k] if session[k] }
|
2011-02-01 09:57:29 +08:00
|
|
|
reset_session
|
2011-11-03 04:59:41 +08:00
|
|
|
saved.each_pair { |k, v| session[k] = v }
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
|
2011-07-16 00:30:31 +08:00
|
|
|
def reset_session_for_login
|
2012-08-01 05:41:13 +08:00
|
|
|
reset_session_saving_keys(:return_to, :oauth2, :confirm, :enrollment, :expected_user_id, :masquerade_return_to)
|
2011-07-16 00:30:31 +08:00
|
|
|
end
|
|
|
|
|
2012-04-04 04:17:56 +08:00
|
|
|
def initiate_delegated_login(current_host=nil)
|
2014-05-07 04:38:56 +08:00
|
|
|
if cookies['canvas_sa_delegated'] && !params[:canvas_login]
|
|
|
|
@domain_root_account = Account.site_admin
|
|
|
|
end
|
2011-06-03 01:26:20 +08:00
|
|
|
is_delegated = @domain_root_account.delegated_authentication? && !params[:canvas_login]
|
2012-12-27 03:55:44 +08:00
|
|
|
is_cas = is_delegated && @domain_root_account.cas_authentication?
|
|
|
|
is_saml = is_delegated && @domain_root_account.saml_authentication?
|
2011-06-03 01:26:20 +08:00
|
|
|
if is_cas
|
|
|
|
initiate_cas_login
|
|
|
|
return true
|
|
|
|
elsif is_saml
|
2012-12-27 03:55:44 +08:00
|
|
|
|
|
|
|
if @domain_root_account.auth_discovery_url
|
|
|
|
redirect_to @domain_root_account.auth_discovery_url
|
|
|
|
else
|
|
|
|
initiate_saml_login(current_host)
|
|
|
|
end
|
|
|
|
|
2011-06-03 01:26:20 +08:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
2014-07-02 06:53:59 +08:00
|
|
|
def cas_client(account = @domain_root_account)
|
|
|
|
@cas_client ||= CASClient::Client.new(
|
|
|
|
cas_base_url: account.account_authorization_config.auth_base,
|
|
|
|
encode_extra_attributes_as: :raw
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
def initiate_cas_login(client = nil)
|
2011-07-16 00:30:31 +08:00
|
|
|
reset_session_for_login
|
2014-07-02 06:53:59 +08:00
|
|
|
client ||= cas_client
|
|
|
|
delegated_auth_redirect(client.add_service_to_login_url(cas_login_url))
|
2011-06-03 01:26:20 +08:00
|
|
|
end
|
|
|
|
|
2012-09-29 06:02:02 +08:00
|
|
|
def initiate_saml_login(current_host=nil, aac=nil)
|
2014-01-27 02:40:00 +08:00
|
|
|
increment_saml_stat("login_attempt")
|
2011-07-16 00:30:31 +08:00
|
|
|
reset_session_for_login
|
2012-09-29 06:02:02 +08:00
|
|
|
aac ||= @domain_root_account.account_authorization_config
|
2012-04-04 04:17:56 +08:00
|
|
|
settings = aac.saml_settings(current_host)
|
2014-11-07 01:57:35 +08:00
|
|
|
request = Onelogin::Saml::AuthRequest.new(settings)
|
|
|
|
forward_url = request.generate_request
|
2012-01-28 09:33:18 +08:00
|
|
|
if aac.debugging? && !aac.debug_get(:request_id)
|
|
|
|
aac.debug_set(:request_id, request.id)
|
2014-11-07 01:57:35 +08:00
|
|
|
aac.debug_set(:to_idp_url, forward_url)
|
|
|
|
aac.debug_set(:to_idp_xml, request.request_xml)
|
2012-01-28 09:33:18 +08:00
|
|
|
aac.debug_set(:debugging, "Forwarding user to IdP for authentication")
|
|
|
|
end
|
2014-11-07 01:57:35 +08:00
|
|
|
delegated_auth_redirect(forward_url)
|
2011-10-28 02:51:15 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def delegated_auth_redirect(uri)
|
2011-12-29 07:07:29 +08:00
|
|
|
redirect_to(delegated_auth_redirect_uri(uri))
|
|
|
|
end
|
|
|
|
|
|
|
|
def delegated_auth_redirect_uri(uri)
|
|
|
|
uri
|
2011-06-03 01:26:20 +08:00
|
|
|
end
|
2014-01-27 02:40:00 +08:00
|
|
|
|
|
|
|
def increment_saml_stat(key)
|
2014-03-05 05:39:04 +08:00
|
|
|
CanvasStatsd::Statsd.increment("saml.#{CanvasStatsd::Statsd.escape(request.host)}.#{key}")
|
2014-01-27 02:40:00 +08:00
|
|
|
end
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|