canvas-lms/app/models/pseudonym_session.rb

114 lines
4.0 KiB
Ruby

#
# Copyright (C) 2011 Instructure, Inc.
#
# 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/>.
#
class PseudonymSession < Authlogic::Session::Base
last_request_at_threshold 10.minutes
verify_password_method :valid_arbitrary_credentials?
login_field :unique_id
find_by_login_method :custom_find_by_unique_id
remember_me_for 2.weeks
attr_accessor :remote_ip, :too_many_attempts
# we need to know if the session came from http basic auth, so we override
# authlogic's method here to add a flag that we can check
def persist_by_http_auth
controller.authenticate_with_http_basic do |login, password|
if !login.blank? && !password.blank?
send("#{login_field}=", login)
send("#{password_field}=", password)
@valid_basic_auth = valid?
return @valid_basic_auth
end
end
false
end
def used_basic_auth?
@valid_basic_auth
end
# modifications to authlogic's cookie persistence (used for the "remember me" token)
# see the SessionPersistenceToken class for details
#
# also, the version of authlogic canvas is on doesn't support httponly (or
# secure-only) for the "remember me" cookie yet, so we add that support here.
def save_cookie
return unless remember_me?
token = SessionPersistenceToken.generate(record)
controller.cookies[cookie_key] = {
:value => token.pseudonym_credentials,
:expires => remember_me_until,
:domain => controller.cookie_domain,
:httponly => true,
:secure => ActionController::Base.session_options[:secure],
}
end
def persist_by_cookie
cookie = controller.cookies[cookie_key]
if cookie
token = SessionPersistenceToken.find_by_pseudonym_credentials(cookie)
self.unauthorized_record = token.use! if token
is_valid = self.valid?
if is_valid
# this token has been used -- destroy it, and generate a new one
# remember_me is implicitly true when they login via the remember_me token
controller.session[:used_remember_me_token] = true
self.remember_me = true
self.save!
end
is_valid
else
false
end
end
# added behavior: destroy the server-side SessionPersistenceToken as well as the browser cookie
def destroy_cookie
cookie = controller.cookies.delete cookie_key, :domain => controller.cookie_domain
return true unless cookie
token = SessionPersistenceToken.find_by_pseudonym_credentials(cookie)
token.try(:destroy)
true
end
# Validate the session using password auth (either local or LDAP, but not
# SSO). If too many failed attempts have occured, the validation will fail.
# In this case, `too_many_attempts?` will be true, rather than
# `invalid_password?`.
#
# Note that for IP based max attempt tracking to occur, you'll need to set
# remote_ip on the PseudonymSession before calling save/valid?. Otherwise,
# only total # of failed attempts will be tracked.
def validate_by_password
super
# have to call super first, as that's what loads attempted_record
if too_many_attempts? || attempted_record.try(:audit_login, remote_ip, !invalid_password?) == :too_many_attempts
self.too_many_attempts = true
errors.add(password_field, I18n.t('errors.max_attempts', 'Too many failed login attempts. Please try again later or contact your system administrator.'))
return
end
end
def too_many_attempts?
too_many_attempts == true
end
end