Start LDAP server with tests, fix various tests and warnings
This commit is contained in:
parent
22805f0fb7
commit
880c04c589
8 changed files with 87 additions and 17 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
58
test/support/ldap_test_environment.ex
Normal file
58
test/support/ldap_test_environment.ex
Normal 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
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue