PageRenderTime 68ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/authentication_methods.rb

https://github.com/kidakaka/canvas-lms
Ruby | 260 lines | 212 code | 23 blank | 25 comment | 57 complexity | c9e79d541a6099798ea0edb58ce7ac4d MD5 | raw file
  1. #
  2. # Copyright (C) 2011 Instructure, Inc.
  3. #
  4. # This file is part of Canvas.
  5. #
  6. # Canvas is free software: you can redistribute it and/or modify it under
  7. # the terms of the GNU Affero General Public License as published by the Free
  8. # Software Foundation, version 3 of the License.
  9. #
  10. # Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
  11. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. # details.
  14. #
  15. # You should have received a copy of the GNU Affero General Public License along
  16. # with this program. If not, see <http://www.gnu.org/licenses/>.
  17. #
  18. module AuthenticationMethods
  19. def authorized(*groups)
  20. authorized_roles = groups
  21. return true
  22. end
  23. def authorized_roles
  24. @authorized_roles ||= []
  25. end
  26. def consume_authorized_roles
  27. authorized_roles = []
  28. end
  29. def load_pseudonym_from_policy
  30. skip_session_save = false
  31. if session.to_hash.empty? && # if there's already some session data, defer to normal auth
  32. (policy_encoded = params['Policy']) &&
  33. (signature = params['Signature']) &&
  34. signature == Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), Attachment.shared_secret, policy_encoded)).gsub(/\n/, '') &&
  35. (policy = JSON.parse(Base64.decode64(policy_encoded)) rescue nil) &&
  36. policy['conditions'] &&
  37. (credential = policy['conditions'].detect{ |cond| cond.is_a?(Hash) && cond.has_key?("pseudonym_id") })
  38. skip_session_save = true
  39. @policy_pseudonym_id = credential['pseudonym_id']
  40. # so that we don't have to explicitly skip verify_authenticity_token
  41. params[self.class.request_forgery_protection_token] ||= form_authenticity_token
  42. end
  43. yield if block_given?
  44. session.destroy if skip_session_save
  45. end
  46. def load_user
  47. if api_request? && params[:access_token]
  48. @access_token = AccessToken.find_by_token(params[:access_token])
  49. @developer_key = @access_token.try(:developer_key)
  50. if !@access_token.try(:usable?)
  51. render :json => {:errors => "Invalid access token"}, :status => :bad_request
  52. return false
  53. end
  54. @current_user = @access_token.user
  55. @current_pseudonym = @current_user.pseudonym
  56. unless @current_user
  57. render :json => {:errors => "Invalid access token"}, :status => :bad_request
  58. return false
  59. end
  60. @access_token.used!
  61. end
  62. if !@access_token
  63. @pseudonym_session = @domain_root_account.pseudonym_session_scope.find
  64. key = @pseudonym_session.send(:session_credentials)[1] rescue nil
  65. if key
  66. @current_pseudonym = Pseudonym.find_cached(['_pseudonym_lookup', key].cache_key) do
  67. @pseudonym_session && @pseudonym_session.record
  68. end
  69. elsif @policy_pseudonym_id
  70. @current_pseudonym = Pseudonym.find_by_id(@policy_pseudonym_id)
  71. else
  72. @current_pseudonym = @pseudonym_session && @pseudonym_session.record
  73. end
  74. if params[:login_success] == '1' && !@current_pseudonym
  75. # they just logged in successfully, but we can't find the pseudonym now?
  76. # sounds like somebody hates cookies.
  77. return redirect_to(login_url(:needs_cookies => '1'))
  78. end
  79. @current_user = @current_pseudonym && @current_pseudonym.user
  80. if api_request?
  81. # only allow api_key to be used if basic auth was sent, not if they're
  82. # just using an app session
  83. @developer_key = DeveloperKey.find_by_api_key(params[:api_key]) if @pseudonym_session.try(:used_basic_auth?) && params[:api_key].present?
  84. @developer_key || request.get? || form_authenticity_token == form_authenticity_param || raise(ApplicationController::InvalidDeveloperAPIKey)
  85. end
  86. end
  87. if @current_user && @current_user.unavailable?
  88. @current_pseudonym = nil
  89. @current_user = nil
  90. end
  91. if @current_user && %w(become_user_id me become_teacher become_student).any? { |k| params.key?(k) }
  92. request_become_user = nil
  93. if params[:become_user_id]
  94. request_become_user = User.find_by_id(params[:become_user_id])
  95. elsif params.keys.include?('me')
  96. request_become_user = @current_user
  97. elsif params.keys.include?('become_teacher')
  98. course = Course.find(params[:course_id] || params[:id]) rescue nil
  99. teacher = course.teachers.first if course
  100. if teacher
  101. request_become_user = teacher
  102. else
  103. flash[:error] = I18n.t('lib.auth.errors.teacher_not_found', "No teacher found")
  104. end
  105. elsif params.keys.include?('become_student')
  106. course = Course.find(params[:course_id] || params[:id]) rescue nil
  107. student = course.students.first if course
  108. if student
  109. request_become_user = student
  110. else
  111. flash[:error] = I18n.t('lib.auth.errors.student_not_found', "No student found")
  112. end
  113. end
  114. if request_become_user && request_become_user.id != session[:become_user_id].to_i && request_become_user.grants_right?(@current_user, session, :become_user)
  115. params_without_become = params.dup
  116. params_without_become.delete_if {|k,v| [ 'become_user_id', 'become_teacher', 'become_student', 'me' ].include? k }
  117. params_without_become[:only_path] = true
  118. session[:masquerade_return_to] = url_for(params_without_become)
  119. return redirect_to user_masquerade_url(request_become_user.id)
  120. end
  121. end
  122. if session[:become_user_id]
  123. user = User.find_by_id(session[:become_user_id])
  124. if user && user.grants_right?(@current_user, session, :become_user)
  125. @real_current_user = @current_user
  126. @current_user = user
  127. logger.warn "#{@real_current_user.name}(#{@real_current_user.id}) impersonating #{@current_user.name} on page #{request.url}"
  128. end
  129. end
  130. @current_user
  131. end
  132. private :load_user
  133. def require_user_for_context
  134. get_context
  135. if !@context
  136. redirect_to '/'
  137. return false
  138. elsif @context.state == 'available'
  139. if !@current_user
  140. respond_to do |format|
  141. store_location
  142. flash[:notice] = I18n.t('lib.auth.errors.not_authenticated', "You must be logged in to access this page")
  143. format.html {redirect_to login_url}
  144. format.json {render :json => {:errors => {:message => I18n.t('lib.auth.errors.not_authenticated', "You must be logged in to access this page")}}, :status => :unauthorized}
  145. end
  146. return false;
  147. elsif !@context.users.include?(@current_user)
  148. respond_to do |format|
  149. flash[:notice] = I18n.t('lib.auth.errors.not_authorized', "You are not authorized to view this page")
  150. format.html {redirect_to "/"}
  151. format.json {render :json => {:errors => {:message => I18n.t('lib.auth.errors.not_authorized', "You are not authorized to view this page")}}, :status => :unauthorized}
  152. end
  153. return false
  154. end
  155. end
  156. end
  157. protected :require_user_for_context
  158. def require_user
  159. unless @current_pseudonym && @current_user
  160. respond_to do |format|
  161. if request.path.match(/getting_started/)
  162. format.html {
  163. store_location
  164. redirect_to register_url
  165. }
  166. else
  167. format.html {
  168. store_location
  169. flash[:notice] = I18n.t('lib.auth.errors.not_authenticated', "You must be logged in to access this page") unless request.path == '/'
  170. redirect_to login_url
  171. }
  172. end
  173. format.json { render :json => {:errors => {:message => I18n.t('lib.auth.authentication_required', "user authorization required")}}.to_json, :status => :unauthorized}
  174. end
  175. return false
  176. end
  177. end
  178. protected :require_user
  179. def store_location(uri=nil, overwrite=true)
  180. if overwrite || !session[:return_to]
  181. session[:return_to] = uri || request.request_uri
  182. end
  183. end
  184. protected :store_location
  185. def redirect_back_or_default(default)
  186. redirect_to(session[:return_to] || default)
  187. session[:return_to] = nil
  188. end
  189. protected :redirect_back_or_default
  190. def redirect_to_referrer_or_default(default)
  191. redirect_to(:back)
  192. rescue ActionController::RedirectBackError
  193. redirect_to(default)
  194. end
  195. # Reset the session, and copy the specified keys over to the new session.
  196. # Please consider the security implications of any keys you copy over.
  197. def reset_session_saving_keys(*keys)
  198. # can't use slice, because session has a different ctor than a normal hash
  199. saved = {}
  200. keys.each { |k| saved[k] = session[k] }
  201. reset_session
  202. session.merge!(saved)
  203. end
  204. def reset_session_for_login
  205. reset_session_saving_keys(:return_to, :oauth2)
  206. end
  207. def initiate_delegated_login
  208. is_delegated = @domain_root_account.delegated_authentication? && !params[:canvas_login]
  209. is_cas = @domain_root_account.cas_authentication? && is_delegated
  210. is_saml = @domain_root_account.saml_authentication? && is_delegated
  211. if is_cas
  212. initiate_cas_login
  213. return true
  214. elsif is_saml
  215. initiate_saml_login
  216. return true
  217. end
  218. false
  219. end
  220. def initiate_cas_login(cas_client = nil)
  221. reset_session_for_login
  222. if @domain_root_account.account_authorization_config.log_in_url.present?
  223. session[:exit_frame] = true
  224. redirect_to(@domain_root_account.account_authorization_config.log_in_url)
  225. else
  226. config = { :cas_base_url => @domain_root_account.account_authorization_config.auth_base }
  227. cas_client ||= CASClient::Client.new(config)
  228. redirect_to(cas_client.add_service_to_login_url(login_url))
  229. end
  230. end
  231. def initiate_saml_login
  232. reset_session_for_login
  233. settings = @domain_root_account.account_authorization_config.saml_settings
  234. request = Onelogin::Saml::AuthRequest.create(settings)
  235. redirect_to(request)
  236. end
  237. end