users: refactor login and authentication logic.
* Make authentication methods into User instance methods instead of class methods. * Fix API key authentication to use a secure string comparison. Fixes a hypothetical (unlikely to be exploitable) timing attack. * Move login logic from SessionCreator to SessionLoader.
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
class SessionCreator
|
||||
attr_reader :session, :name, :password, :ip_addr
|
||||
attr_reader :user
|
||||
|
||||
def initialize(session, name, password, ip_addr)
|
||||
@session = session
|
||||
@name = name
|
||||
@password = password
|
||||
@ip_addr = ip_addr
|
||||
end
|
||||
|
||||
def authenticate
|
||||
if User.authenticate(name, password)
|
||||
@user = User.find_by_name(name)
|
||||
|
||||
session[:user_id] = @user.id
|
||||
@user.update_column(:last_ip_addr, ip_addr)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -9,6 +9,15 @@ class SessionLoader
|
||||
@params = request.parameters
|
||||
end
|
||||
|
||||
def login(name, password)
|
||||
user = User.find_by_name(name)&.authenticate_password(password)
|
||||
return nil unless user
|
||||
|
||||
session[:user_id] = user.id
|
||||
user.update_column(:last_ip_addr, request.remote_ip)
|
||||
user
|
||||
end
|
||||
|
||||
def load
|
||||
CurrentUser.user = User.anonymous
|
||||
CurrentUser.ip_addr = request.remote_ip
|
||||
@@ -50,8 +59,6 @@ class SessionLoader
|
||||
authenticate_api_key(params[:login], params[:api_key])
|
||||
elsif params[:login].present? && params[:password_hash].present?
|
||||
authenticate_legacy_api_key(params[:login], params[:password_hash])
|
||||
else
|
||||
raise AuthenticationFailure
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,11 +70,8 @@ class SessionLoader
|
||||
end
|
||||
|
||||
def authenticate_api_key(name, api_key)
|
||||
CurrentUser.user = User.authenticate_api_key(name, api_key)
|
||||
|
||||
if CurrentUser.user.nil?
|
||||
raise AuthenticationFailure.new
|
||||
end
|
||||
CurrentUser.user = User.find_by_name(name)&.authenticate_api_key(api_key)
|
||||
raise AuthenticationFailure unless Currentuser.user.present?
|
||||
end
|
||||
|
||||
def authenticate_legacy_api_key(name, password_hash)
|
||||
|
||||
@@ -62,7 +62,7 @@ class UserDeletion
|
||||
end
|
||||
|
||||
def validate
|
||||
if !User.authenticate(user.name, password)
|
||||
if !user.authenticate_password(password)
|
||||
raise ValidationError.new("Password is incorrect")
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user