Start LDAP server with tests, fix various tests and warnings

This commit is contained in:
Timothée Floure 2021-01-07 08:15:09 +01:00
parent 22805f0fb7
commit 880c04c589
Signed by: tfloure
GPG key ID: 4502C902C00A1E12
8 changed files with 87 additions and 17 deletions

View file

@ -96,7 +96,8 @@ defmodule RecycledCloud.LDAP do
:eldap.simple_bind(ldap_conn, dn, pw) :eldap.simple_bind(ldap_conn, dn, pw)
end end
defp connect do # The method is used by the RC.LDAPTestEnvironment module.
def connect do
conf = Application.get_env(:recycledcloud, :ldap, []) conf = Application.get_env(:recycledcloud, :ldap, [])
host = Keyword.get(conf, :server, "localhost") |> String.to_charlist host = Keyword.get(conf, :server, "localhost") |> String.to_charlist
@ -110,18 +111,19 @@ defmodule RecycledCloud.LDAP do
Logger.info "Successfuly connected to LDAP server." Logger.info "Successfuly connected to LDAP server."
case bind(ldap_conn) do case bind(ldap_conn) do
{:error, err} -> {:error, err} ->
Logger.warning("Could not bind to LDAP server: #{err}") Logger.warning("Could not bind to LDAP server: #{inspect(err)}")
_ -> :noop _ -> :noop
end end
%{status: :ok, conn: ldap_conn} %{status: :ok, conn: ldap_conn}
{:error, err} -> {: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} %{status: :error, conn: nil}
end end
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 ldap_conn |> :eldap.close
Logger.debug("An LDAP connection was closed.") Logger.debug("An LDAP connection was closed.")
end end

View file

@ -6,7 +6,6 @@ defmodule RecycledCloud.Accounts do
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias RecycledCloud.Repo alias RecycledCloud.Repo
alias RecycledCloud.Accounts.{User, Key, UserToken, UserNotifier} alias RecycledCloud.Accounts.{User, Key, UserToken, UserNotifier}
alias RecycledCloud.LDAP
## Database getters ## Database getters
@ -164,7 +163,7 @@ defmodule RecycledCloud.Accounts do
:ok <- User.set_email(user, email) do :ok <- User.set_email(user, email) do
:ok :ok
else else
err -> :error _ -> :error
end end
end end

View file

@ -40,7 +40,7 @@ defmodule RecycledCloud.Accounts.Key do
@doc false @doc false
def changeset(key, attrs) do def changeset(key, attrs) do
out = key key
|> cast(attrs, [:comment, :value]) |> cast(attrs, [:comment, :value])
|> validate_required([:value]) |> validate_required([:value])
|> process_ssh_key(:value, :fingerprint, :comment) |> process_ssh_key(:value, :fingerprint, :comment)

View file

@ -30,7 +30,7 @@ defmodule RecycledCloud.Accounts.User do
case query |> LDAP.execute do case query |> LDAP.execute do
{:ok, []} -> {:error, "could not find matching object"} {:ok, []} -> {:error, "could not find matching object"}
{:ok, [entry]} -> {:ok, entry} {: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)} {:error, err} -> {:error, inspect(err)}
end end
end end
@ -85,7 +85,7 @@ defmodule RecycledCloud.Accounts.User do
err -> err err -> err
end end
end end
o = query |> LDAP.execute query |> LDAP.execute
end end
def register(%User{} = user) do def register(%User{} = user) do

View file

@ -7,8 +7,8 @@ defmodule RecycledCloudWeb.UserConfirmationController do
render(conn, "new.html") render(conn, "new.html")
end end
def create(conn, %{"user" => %{"email" => email}}) do def create(conn, %{"user" => %{"username" => username}}) do
if user = Accounts.get_user_by_email(email) do if user = Accounts.get_user_by_username(username) do
Accounts.deliver_user_confirmation_instructions( Accounts.deliver_user_confirmation_instructions(
user, user,
&Routes.user_confirmation_url(conn, :confirm, &1) &Routes.user_confirmation_url(conn, :confirm, &1)

View file

@ -35,7 +35,7 @@ defmodule RecycledCloudWeb.UserSettingsControllerTest do
assert redirected_to(new_password_conn) == Routes.user_settings_path(conn, :edit) 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_session(new_password_conn, :user_token) != get_session(conn, :user_token)
assert get_flash(new_password_conn, :info) =~ "Password updated successfully" 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 end
test "does not update password on invalid data", %{conn: conn} do test "does not update password on invalid data", %{conn: conn} do
@ -44,14 +44,13 @@ defmodule RecycledCloudWeb.UserSettingsControllerTest do
"action" => "update_password", "action" => "update_password",
"current_password" => "invalid", "current_password" => "invalid",
"user" => %{ "user" => %{
"password" => "too short", "password" => "short",
"password_confirmation" => "does not match" "password_confirmation" => "does not match"
} }
}) })
response = html_response(old_password_conn, 200) response = html_response(old_password_conn, 200)
assert response =~ "<h1>Settings</h1>" assert response =~ "should be at least 6 character(s)"
assert response =~ "should be at least 12 character(s)"
assert response =~ "does not match password" assert response =~ "does not match password"
assert response =~ "is not valid" assert response =~ "is not valid"

View file

@ -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

View file

@ -1,2 +1,14 @@
ExUnit.start() require Logger
Ecto.Adapters.SQL.Sandbox.mode(RecycledCloud.Repo, :manual)
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