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:
evazion
2020-03-25 03:41:27 -05:00
parent 64af957031
commit b2cf765d6d
14 changed files with 68 additions and 100 deletions

View File

@@ -18,8 +18,8 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
put_auth user_password_path(@user), @user, params: { user: { old_password: "12345", password: "abcde", password_confirmation: "abcde" } }
assert_redirected_to @user
assert_equal(nil, User.authenticate(@user.name, "12345"))
assert_equal(@user, User.authenticate(@user.name, "abcde"))
assert_equal(false, @user.reload.authenticate_password("12345"))
assert_equal(@user, @user.authenticate_password("abcde"))
end
should "update the password when given a valid login key" do
@@ -27,24 +27,24 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
put_auth user_password_path(@user), @user, params: { user: { password: "abcde", password_confirmation: "abcde", signed_user_id: signed_user_id } }
assert_redirected_to @user
assert_equal(nil, User.authenticate(@user.name, "12345"))
assert_equal(@user, User.authenticate(@user.name, "abcde"))
assert_equal(false, @user.reload.authenticate_password("12345"))
assert_equal(@user, @user.authenticate_password("abcde"))
end
should "not update the password when given an invalid old password" do
put_auth user_password_path(@user), @user, params: { user: { old_password: "3qoirjqe", password: "abcde", password_confirmation: "abcde" } }
assert_response :success
assert_equal(@user, User.authenticate(@user.name, "12345"))
assert_equal(nil, User.authenticate(@user.name, "abcde"))
assert_equal(@user, @user.reload.authenticate_password("12345"))
assert_equal(false, @user.authenticate_password("abcde"))
end
should "not update the password when password confirmation fails for the new password" do
put_auth user_password_path(@user), @user, params: { user: { old_password: "12345", password: "abcde", password_confirmation: "qerogijqe" } }
assert_response :success
assert_equal(@user, User.authenticate(@user.name, "12345"))
assert_equal(nil, User.authenticate(@user.name, "abcde"))
assert_equal(@user, @user.reload.authenticate_password("12345"))
assert_equal(false, @user.authenticate_password("abcde"))
end
end
end

View File

@@ -3,7 +3,7 @@ require 'test_helper'
class SessionsControllerTest < ActionDispatch::IntegrationTest
context "the sessions controller" do
setup do
@user = create(:user)
@user = create(:user, password: "password")
end
context "new action" do
@@ -14,15 +14,27 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
end
context "create action" do
should "create a new session" do
post session_path, params: {:name => @user.name, :password => "password"}
should "log the user in when given the correct password" do
post session_path, params: { name: @user.name, password: "password" }
assert_redirected_to posts_path
assert_equal(@user.id, session[:user_id])
assert_not_nil(@user.reload.last_ip_addr)
end
should "not allow IP banned users to create a new session" do
should "not log the user in when given an incorrect password" do
post session_path, params: { name: @user.name, password: "wrong"}
assert_response 401
assert_nil(nil, session[:user_id])
end
should "redirect the user when given an url param" do
post session_path, params: { name: @user.name, password: "password", url: tags_path }
assert_redirected_to tags_path
end
should "not allow IP banned users to login" do
create(:ip_ban, ip_addr: "1.2.3.4")
post session_path, params: { name: @user.name, password: "password" }, headers: { REMOTE_ADDR: "1.2.3.4" }

View File

@@ -118,7 +118,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to User.last
assert_equal("xxx", User.last.name)
assert_equal(User.last, User.authenticate("xxx", "xxxxx1"))
assert_equal(User.last, User.last.authenticate_password("xxxxx1"))
assert_equal(nil, User.last.email_address)
assert_no_enqueued_emails
end
@@ -128,7 +128,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to User.last
assert_equal("xxx", User.last.name)
assert_equal(User.last, User.authenticate("xxx", "xxxxx1"))
assert_equal(User.last, User.last.authenticate_password("xxxxx1"))
assert_equal("webmaster@danbooru.donmai.us", User.last.email_address.address)
assert_enqueued_email_with UserMailer, :welcome_user, args: [User.last]
end