From 880c04c58968b318fe3f6a41d251f7e0f14a28ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 Jan 2021 08:15:09 +0100 Subject: [PATCH] Start LDAP server with tests, fix various tests and warnings --- lib/recycledcloud/LDAP.ex | 10 ++-- lib/recycledcloud/accounts.ex | 3 +- lib/recycledcloud/accounts/key.ex | 2 +- lib/recycledcloud/accounts/user.ex | 4 +- .../user_confirmation_controller.ex | 4 +- .../user_settings_controller_test.exs | 7 +-- test/support/ldap_test_environment.ex | 58 +++++++++++++++++++ test/test_helper.exs | 16 ++++- 8 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 test/support/ldap_test_environment.ex diff --git a/lib/recycledcloud/LDAP.ex b/lib/recycledcloud/LDAP.ex index 955cbfe..1f2435f 100644 --- a/lib/recycledcloud/LDAP.ex +++ b/lib/recycledcloud/LDAP.ex @@ -96,7 +96,8 @@ defmodule RecycledCloud.LDAP do :eldap.simple_bind(ldap_conn, dn, pw) end - defp connect do + # The method is used by the RC.LDAPTestEnvironment module. + def connect do conf = Application.get_env(:recycledcloud, :ldap, []) host = Keyword.get(conf, :server, "localhost") |> String.to_charlist @@ -110,18 +111,19 @@ defmodule RecycledCloud.LDAP do Logger.info "Successfuly connected to LDAP server." case bind(ldap_conn) do {:error, err} -> - Logger.warning("Could not bind to LDAP server: #{err}") + Logger.warning("Could not bind to LDAP server: #{inspect(err)}") _ -> :noop end %{status: :ok, conn: ldap_conn} {:error, err} -> - Logger.warning "Failed to connect to LDAP server: #{err}. Authentication will not be possible." + Logger.warning "Failed to connect to LDAP server: #{inspect(err)}. Authentication will not be possible." %{status: :error, conn: nil} end end - defp close(ldap_conn) do + # The method is used by the RC.LDAPTestEnvironment module. + def close(ldap_conn) do ldap_conn |> :eldap.close Logger.debug("An LDAP connection was closed.") end diff --git a/lib/recycledcloud/accounts.ex b/lib/recycledcloud/accounts.ex index 0464271..9e68c55 100644 --- a/lib/recycledcloud/accounts.ex +++ b/lib/recycledcloud/accounts.ex @@ -6,7 +6,6 @@ defmodule RecycledCloud.Accounts do import Ecto.Query, warn: false alias RecycledCloud.Repo alias RecycledCloud.Accounts.{User, Key, UserToken, UserNotifier} - alias RecycledCloud.LDAP ## Database getters @@ -164,7 +163,7 @@ defmodule RecycledCloud.Accounts do :ok <- User.set_email(user, email) do :ok else - err -> :error + _ -> :error end end diff --git a/lib/recycledcloud/accounts/key.ex b/lib/recycledcloud/accounts/key.ex index 7fd2a37..6410969 100644 --- a/lib/recycledcloud/accounts/key.ex +++ b/lib/recycledcloud/accounts/key.ex @@ -40,7 +40,7 @@ defmodule RecycledCloud.Accounts.Key do @doc false def changeset(key, attrs) do - out = key + key |> cast(attrs, [:comment, :value]) |> validate_required([:value]) |> process_ssh_key(:value, :fingerprint, :comment) diff --git a/lib/recycledcloud/accounts/user.ex b/lib/recycledcloud/accounts/user.ex index 0558be1..0a51a93 100644 --- a/lib/recycledcloud/accounts/user.ex +++ b/lib/recycledcloud/accounts/user.ex @@ -30,7 +30,7 @@ defmodule RecycledCloud.Accounts.User do case query |> LDAP.execute do {:ok, []} -> {:error, "could not find matching object"} {:ok, [entry]} -> {:ok, entry} - {:ok, [entry|_]} -> {:error, "found more than one object with uid #{uid}"} + {:ok, [_entry|_]} -> {:error, "found more than one object with uid #{uid}"} {:error, err} -> {:error, inspect(err)} end end @@ -85,7 +85,7 @@ defmodule RecycledCloud.Accounts.User do err -> err end end - o = query |> LDAP.execute + query |> LDAP.execute end def register(%User{} = user) do diff --git a/lib/recycledcloud_web/controllers/user_confirmation_controller.ex b/lib/recycledcloud_web/controllers/user_confirmation_controller.ex index aff5d85..66b6021 100644 --- a/lib/recycledcloud_web/controllers/user_confirmation_controller.ex +++ b/lib/recycledcloud_web/controllers/user_confirmation_controller.ex @@ -7,8 +7,8 @@ defmodule RecycledCloudWeb.UserConfirmationController do render(conn, "new.html") end - def create(conn, %{"user" => %{"email" => email}}) do - if user = Accounts.get_user_by_email(email) do + def create(conn, %{"user" => %{"username" => username}}) do + if user = Accounts.get_user_by_username(username) do Accounts.deliver_user_confirmation_instructions( user, &Routes.user_confirmation_url(conn, :confirm, &1) diff --git a/test/recycledcloud_web/controllers/user_settings_controller_test.exs b/test/recycledcloud_web/controllers/user_settings_controller_test.exs index 5f108e7..5b91fa6 100644 --- a/test/recycledcloud_web/controllers/user_settings_controller_test.exs +++ b/test/recycledcloud_web/controllers/user_settings_controller_test.exs @@ -35,7 +35,7 @@ defmodule RecycledCloudWeb.UserSettingsControllerTest do assert redirected_to(new_password_conn) == Routes.user_settings_path(conn, :edit) assert get_session(new_password_conn, :user_token) != get_session(conn, :user_token) assert get_flash(new_password_conn, :info) =~ "Password updated successfully" - assert Accounts.get_user_by_email_and_password(user.email, "new valid password") + assert Accounts.get_user_by_username_and_password(user.username, "new valid password") end test "does not update password on invalid data", %{conn: conn} do @@ -44,14 +44,13 @@ defmodule RecycledCloudWeb.UserSettingsControllerTest do "action" => "update_password", "current_password" => "invalid", "user" => %{ - "password" => "too short", + "password" => "short", "password_confirmation" => "does not match" } }) response = html_response(old_password_conn, 200) - assert response =~ "

Settings

" - assert response =~ "should be at least 12 character(s)" + assert response =~ "should be at least 6 character(s)" assert response =~ "does not match password" assert response =~ "is not valid" diff --git a/test/support/ldap_test_environment.ex b/test/support/ldap_test_environment.ex new file mode 100644 index 0000000..ffcbeb4 --- /dev/null +++ b/test/support/ldap_test_environment.ex @@ -0,0 +1,58 @@ +defmodule RecycledCloud.LDAPTestEnvironment do + alias RecycledCloud.LDAP + require Logger + + @image "code.ungleich.ch:5050/fnux/e-durable-oci-images/openldap-playground:latest" + + def start() do + case System.find_executable("podman") do + nil -> + Logger.error("Could not find podman executable (required for LDAP environment). Exiting.") + + :error + podman -> + Logger.info("Starting LDAP environment.") + container = container_name() + port = Port.open( + {:spawn_executable, podman}, + [:binary, args: [ + "run", "--rm", "--name", container, "-p", "3089:389", @image + ]]) + + case wait_for_ldap() do + :ok -> + # Wait for LDAP server to be populated. + # FIXME: poll state instead of taking a nap! + Process.sleep(1000) + + {:ok, port, container} + :timeout -> {:error, :timeout} + end + end + end + + def stop(name) do + Logger.info "Terminating LDAP Test Environment." + + podman = System.find_executable("podman") + System.cmd(podman, ["stop", name]) + end + + defp container_name, do: "ldap-playground-#{System.unique_integer()}" + + defp wait_for_ldap(poll_every \\ 1000, max \\ 10, current \\ 0) do + case LDAP.connect() do + %{status: :ok, conn: conn} -> + conn |> LDAP.close() + :ok + + %{status: :error, conn: _} -> + unless current >= max do + Process.sleep(poll_every) + wait_for_ldap(poll_every, max, current + 1) + else + :timeout + end + end + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs index b530076..32f009e 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,2 +1,14 @@ -ExUnit.start() -Ecto.Adapters.SQL.Sandbox.mode(RecycledCloud.Repo, :manual) +require Logger + +case RecycledCloud.LDAPTestEnvironment.start() do + {:ok, _port, name} -> + ExUnit.start() + Ecto.Adapters.SQL.Sandbox.mode(RecycledCloud.Repo, :manual) + + System.at_exit(fn _code -> + RecycledCloud.LDAPTestEnvironment.stop(name) + end) + {:error, _err} -> + Logger.error("Could not start LDAP Test Environment.") + System.stop(1) +end