summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimponic <loganhunt@simponic.xyz>2022-12-19 20:45:01 -0700
committerSimponic <loganhunt@simponic.xyz>2022-12-19 20:45:01 -0700
commit110eb0b1990d5d5ee77f9368a9b7653cfdc07131 (patch)
treebfe5744255cdfbdc9412d148236a2bf5f8aad7c1
parentfe661a935ac887b11aec31ff049ace2db7ccbf84 (diff)
downloadchessh-110eb0b1990d5d5ee77f9368a9b7653cfdc07131.tar.gz
chessh-110eb0b1990d5d5ee77f9368a9b7653cfdc07131.zip
Implement public key and add tests
-rw-r--r--config/config.exs4
-rw-r--r--lib/chessh/auth/keys.ex17
-rw-r--r--lib/chessh/auth/password.ex4
-rw-r--r--lib/chessh/schema/key.ex1
-rw-r--r--lib/chessh/schema/player.ex2
-rw-r--r--test/auth/password_test.exs27
-rw-r--r--test/auth/pubkey_test.exs35
-rw-r--r--test/schema/key_test.exs1
-rw-r--r--test/schema/register_test.exs51
-rw-r--r--test/support/repo_case.ex2
10 files changed, 133 insertions, 11 deletions
diff --git a/config/config.exs b/config/config.exs
index bafbdfe..6fb4258 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -8,6 +8,8 @@ config :esshd,
handler: {Chessh.Shell, :on_shell, 4},
port: 42069,
password_authenticator: Chessh.Auth.PasswordAuthenticator,
- public_key_authenticator: Chessh.Auth.KeyAuthenticator
+ public_key_authenticator: Chessh.Auth.KeyAuthenticator,
+ # TODO - benchmark
+ max_sessions: 128
import_config "#{config_env()}.exs"
diff --git a/lib/chessh/auth/keys.ex b/lib/chessh/auth/keys.ex
index d85f4a4..a948fdf 100644
--- a/lib/chessh/auth/keys.ex
+++ b/lib/chessh/auth/keys.ex
@@ -1,10 +1,19 @@
defmodule Chessh.Auth.KeyAuthenticator do
+ alias Chessh.Key
+ alias Chessh.Repo
use Sshd.PublicKeyAuthenticator
require Logger
+ import Ecto.Query
- def authenticate(username, public_key, _opts) do
- Logger.debug("#{inspect(username)}")
- Logger.debug("#{inspect(public_key)}")
- true
+ def authenticate(username, public_key) do
+ !!Repo.one(
+ from(k in Key,
+ join: p in assoc(k, :player),
+ where: k.key == ^Key.encode_key(public_key),
+ where: p.username == ^String.Chars.to_string(username)
+ )
+ )
end
+
+ def authenticate(username, public_key, _opts), do: authenticate(username, public_key)
end
diff --git a/lib/chessh/auth/password.ex b/lib/chessh/auth/password.ex
index a6fa73d..48a4d62 100644
--- a/lib/chessh/auth/password.ex
+++ b/lib/chessh/auth/password.ex
@@ -2,11 +2,11 @@ defmodule Chessh.Auth.PasswordAuthenticator do
alias Chessh.Player
alias Chessh.Repo
use Sshd.PasswordAuthenticator
+ require Logger
def authenticate(username, password) do
case Repo.get_by(Player, username: String.Chars.to_string(username)) do
- nil -> false
- x -> Player.valid_password?(x, password)
+ x -> Player.valid_password?(x, String.Chars.to_string(password))
end
end
end
diff --git a/lib/chessh/schema/key.ex b/lib/chessh/schema/key.ex
index f8c14cf..765c83b 100644
--- a/lib/chessh/schema/key.ex
+++ b/lib/chessh/schema/key.ex
@@ -32,6 +32,7 @@ defmodule Chessh.Key do
if is_tuple(key) do
case key do
{pub, [opts]} -> [{pub, [opts]}]
+ {pub, []} -> [{pub, [comment: '']}]
key -> [{key, [comment: '']}]
end
|> :ssh_file.encode(:openssh_key)
diff --git a/lib/chessh/schema/player.ex b/lib/chessh/schema/player.ex
index d04ed3e..5b7b904 100644
--- a/lib/chessh/schema/player.ex
+++ b/lib/chessh/schema/player.ex
@@ -49,7 +49,7 @@ defmodule Chessh.Player do
defp validate_username(changeset) do
changeset
|> validate_required([:username])
- |> validate_length(:username, min: 2, max: 12)
+ |> validate_length(:username, min: 2, max: 16)
|> validate_format(:username, ~r/^[a-zA-Z0-9_\-]*$/,
message: "only letters, numbers, underscores, and hyphens allowed"
)
diff --git a/test/auth/password_test.exs b/test/auth/password_test.exs
new file mode 100644
index 0000000..974f2fa
--- /dev/null
+++ b/test/auth/password_test.exs
@@ -0,0 +1,27 @@
+defmodule Chessh.Auth.PasswordAuthenticatorTest do
+ use ExUnit.Case
+ alias Chessh.Player
+ alias Chessh.Repo
+
+ @valid_user %{username: "logan", password: "password"}
+
+ setup do
+ :ok = Ecto.Adapters.SQL.Sandbox.checkout(Chessh.Repo)
+
+ {:ok, _user} = Repo.insert(Player.registration_changeset(%Player{}, @valid_user))
+
+ :ok
+ end
+
+ test "User can sign in with their password" do
+ assert Chessh.Auth.PasswordAuthenticator.authenticate(
+ String.to_charlist(@valid_user.username),
+ String.to_charlist(@valid_user.password)
+ )
+
+ refute Chessh.Auth.PasswordAuthenticator.authenticate(
+ String.to_charlist(@valid_user.username),
+ String.to_charlist("a_bad_password")
+ )
+ end
+end
diff --git a/test/auth/pubkey_test.exs b/test/auth/pubkey_test.exs
new file mode 100644
index 0000000..78eecfb
--- /dev/null
+++ b/test/auth/pubkey_test.exs
@@ -0,0 +1,35 @@
+defmodule Chessh.Auth.PublicKeyAuthenticatorTest do
+ use ExUnit.Case
+ alias Chessh.Key
+ alias Chessh.Repo
+ alias Chessh.Player
+
+ @valid_user %{username: "logan", password: "password"}
+ @valid_key %{
+ name: "The Gamer Machine",
+ key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ/2LOJGGEd/dhFgRxJ5MMv0jJw4s4pA8qmMbZyulN44"
+ }
+
+ setup do
+ :ok = Ecto.Adapters.SQL.Sandbox.checkout(Chessh.Repo)
+
+ {:ok, player} = Repo.insert(Player.registration_changeset(%Player{}, @valid_user))
+
+ {:ok, _key} =
+ Repo.insert(
+ Key.changeset(%Key{}, @valid_key)
+ |> Ecto.Changeset.put_assoc(:player, player)
+ )
+
+ :ok
+ end
+
+ test "User can sign in with their ssh key from raw string" do
+ assert Chessh.Auth.KeyAuthenticator.authenticate(@valid_user.username, @valid_key.key)
+ end
+
+ test "User can sign in with erlang decoded ssh key" do
+ [key] = :ssh_file.decode(@valid_key.key, :openssh_key)
+ assert Chessh.Auth.KeyAuthenticator.authenticate(@valid_user.username, key)
+ end
+end
diff --git a/test/schema/key_test.exs b/test/schema/key_test.exs
index 2c5409d..6dbb574 100644
--- a/test/schema/key_test.exs
+++ b/test/schema/key_test.exs
@@ -28,7 +28,6 @@ defmodule Chessh.Schema.KeyTest do
@empty_attrs %{}
test "changeset with valid attributes" do
- IO.puts(inspect(Key.changeset(%Key{}, @valid_attrs)))
assert Key.changeset(%Key{}, @valid_attrs).valid?
assert Key.changeset(%Key{}, @valid_key_attrs).valid?
end
diff --git a/test/schema/register_test.exs b/test/schema/register_test.exs
new file mode 100644
index 0000000..5705d31
--- /dev/null
+++ b/test/schema/register_test.exs
@@ -0,0 +1,51 @@
+defmodule Chessh.Auth.UserRegistrationTest do
+ use Chessh.RepoCase
+ use ExUnit.Case
+ alias Chessh.Player
+ alias Chessh.Repo
+
+ @valid_user %{username: "logan", password: "password"}
+ @invalid_username %{username: "a", password: "password"}
+ @invalid_password %{username: "aasdf", password: "pass"}
+ @repeated_username %{username: "LoGan", password: "password"}
+
+ test "Password must be at least 8 characters and username must be at least 2" do
+ refute Player.registration_changeset(%Player{}, @invalid_password).valid?
+ refute Player.registration_changeset(%Player{}, @invalid_username).valid?
+ end
+
+ test "Password changeset must match" do
+ refute Player.password_changeset(
+ %Player{},
+ Map.put(@valid_user, :password_confirmation,
+ password_confirmation: @valid_user.password <> "a"
+ )
+ ).valid?
+
+ valid_user_changed_password = Map.put(@valid_user, :password, "a_new_password")
+
+ assert Player.password_changeset(
+ %Player{},
+ Map.put(
+ valid_user_changed_password,
+ :password_confirmation,
+ valid_user_changed_password.password
+ )
+ ).valid?
+ end
+
+ test "Password is hashed" do
+ changeset = Player.registration_changeset(%Player{}, @valid_user)
+ assert_raise KeyError, fn -> changeset.changes.password end
+ assert changeset.changes.hashed_password
+ refute changeset.changes.hashed_password == @valid_user.password
+ end
+
+ test "Username is uniquely case insensitive" do
+ assert Repo.insert(Player.registration_changeset(%Player{}, @valid_user))
+
+ assert {:error,
+ %{errors: [{:username, {_, [{:constraint, :unique}, {:constraint_name, _}]}}]}} =
+ Repo.insert(Player.registration_changeset(%Player{}, @repeated_username))
+ end
+end
diff --git a/test/support/repo_case.ex b/test/support/repo_case.ex
index 73abcff..e5f4a6f 100644
--- a/test/support/repo_case.ex
+++ b/test/support/repo_case.ex
@@ -8,8 +8,6 @@ defmodule Chessh.RepoCase do
import Ecto
import Ecto.Query
import Chessh.RepoCase
-
- # and any other stuff
end
end