2020-06-27 17:12:45 +00:00
|
|
|
defmodule Mobilizon.Service.Auth.LDAPAuthenticatorTest do
|
|
|
|
use Mobilizon.Web.ConnCase
|
|
|
|
use Mobilizon.Tests.Helpers
|
|
|
|
|
|
|
|
alias Mobilizon.GraphQL.AbsintheHelpers
|
|
|
|
alias Mobilizon.Service.Auth.{Authenticator, LDAPAuthenticator}
|
|
|
|
alias Mobilizon.Users.User
|
|
|
|
alias Mobilizon.Web.Auth.Guardian
|
|
|
|
|
|
|
|
import Mobilizon.Factory
|
|
|
|
import ExUnit.CaptureLog
|
|
|
|
import Mock
|
|
|
|
|
|
|
|
@skip if !Code.ensure_loaded?(:eldap), do: :skip
|
|
|
|
@admin_password "admin_password"
|
|
|
|
|
|
|
|
setup_all do
|
|
|
|
clear_config([:ldap, :enabled], true)
|
|
|
|
clear_config([:ldap, :bind_uid], "admin")
|
|
|
|
clear_config([:ldap, :bind_password], @admin_password)
|
|
|
|
end
|
|
|
|
|
|
|
|
setup_all do:
|
|
|
|
clear_config(
|
|
|
|
Authenticator,
|
|
|
|
LDAPAuthenticator
|
|
|
|
)
|
|
|
|
|
|
|
|
@login_mutation """
|
|
|
|
mutation Login($email: String!, $password: String!) {
|
|
|
|
login(email: $email, password: $password) {
|
|
|
|
accessToken,
|
|
|
|
refreshToken,
|
|
|
|
user {
|
|
|
|
id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
|
|
|
|
describe "login" do
|
|
|
|
@tag @skip
|
|
|
|
test "authorizes the existing user using LDAP credentials", %{conn: conn} do
|
|
|
|
user_password = "testpassword"
|
|
|
|
admin_password = "admin_password"
|
|
|
|
user = insert(:user, password_hash: Argon2.hash_pwd_salt(user_password))
|
|
|
|
|
|
|
|
host = [:ldap, :host] |> Mobilizon.Config.get() |> to_charlist
|
|
|
|
port = Mobilizon.Config.get([:ldap, :port])
|
|
|
|
|
|
|
|
with_mocks [
|
|
|
|
{:eldap, [],
|
|
|
|
[
|
|
|
|
open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end,
|
|
|
|
simple_bind: fn _connection, _dn, password ->
|
|
|
|
case password do
|
|
|
|
^admin_password -> :ok
|
|
|
|
^user_password -> :ok
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
equalityMatch: fn _type, _value -> :ok end,
|
|
|
|
wholeSubtree: fn -> :ok end,
|
|
|
|
search: fn _connection, _options ->
|
|
|
|
{:ok,
|
2023-08-17 11:18:01 +00:00
|
|
|
{:eldap_search_result, [{:eldap_entry, ~c"", [{~c"cn", [to_charlist("MyUser")]}]}],
|
|
|
|
[], []}}
|
2020-06-27 17:12:45 +00:00
|
|
|
end,
|
|
|
|
close: fn _connection ->
|
|
|
|
send(self(), :close_connection)
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
]}
|
|
|
|
] do
|
|
|
|
res =
|
|
|
|
conn
|
|
|
|
|> AbsintheHelpers.graphql_query(
|
|
|
|
query: @login_mutation,
|
|
|
|
variables: %{email: user.email, password: user_password}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert is_nil(res["error"])
|
|
|
|
assert token = res["data"]["login"]["accessToken"]
|
|
|
|
|
|
|
|
{:ok, %User{} = user_from_token, _claims} = Guardian.resource_from_token(token)
|
|
|
|
|
|
|
|
assert user_from_token.id == user.id
|
|
|
|
assert_received :close_connection
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@tag @skip
|
|
|
|
test "creates a new user after successful LDAP authorization", %{conn: conn} do
|
|
|
|
user_password = "testpassword"
|
|
|
|
admin_password = "admin_password"
|
|
|
|
user = build(:user)
|
|
|
|
|
|
|
|
host = [:ldap, :host] |> Mobilizon.Config.get() |> to_charlist
|
|
|
|
port = Mobilizon.Config.get([:ldap, :port])
|
|
|
|
|
|
|
|
with_mocks [
|
|
|
|
{:eldap, [],
|
|
|
|
[
|
|
|
|
open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end,
|
|
|
|
simple_bind: fn _connection, _dn, password ->
|
|
|
|
case password do
|
|
|
|
^admin_password -> :ok
|
|
|
|
^user_password -> :ok
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
equalityMatch: fn _type, _value -> :ok end,
|
|
|
|
wholeSubtree: fn -> :ok end,
|
|
|
|
search: fn _connection, _options ->
|
|
|
|
{:ok,
|
2023-08-17 11:18:01 +00:00
|
|
|
{:eldap_search_result, [{:eldap_entry, ~c"", [{~c"cn", [to_charlist("MyUser")]}]}],
|
|
|
|
[], []}}
|
2020-06-27 17:12:45 +00:00
|
|
|
end,
|
|
|
|
close: fn _connection ->
|
|
|
|
send(self(), :close_connection)
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
]}
|
|
|
|
] do
|
|
|
|
res =
|
|
|
|
conn
|
|
|
|
|> AbsintheHelpers.graphql_query(
|
|
|
|
query: @login_mutation,
|
|
|
|
variables: %{email: user.email, password: user_password}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert is_nil(res["error"])
|
|
|
|
assert token = res["data"]["login"]["accessToken"]
|
|
|
|
|
|
|
|
{:ok, %User{} = user_from_token, _claims} = Guardian.resource_from_token(token)
|
|
|
|
|
|
|
|
assert user_from_token.email == user.email
|
|
|
|
assert_received :close_connection
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@tag @skip
|
|
|
|
test "falls back to the default authorization when LDAP is unavailable", %{conn: conn} do
|
|
|
|
user_password = "testpassword"
|
|
|
|
admin_password = "admin_password"
|
|
|
|
user = insert(:user, password_hash: Argon2.hash_pwd_salt(user_password))
|
|
|
|
|
|
|
|
host = [:ldap, :host] |> Mobilizon.Config.get() |> to_charlist
|
|
|
|
port = Mobilizon.Config.get([:ldap, :port])
|
|
|
|
|
|
|
|
with_mocks [
|
|
|
|
{:eldap, [],
|
|
|
|
[
|
2023-08-17 11:18:01 +00:00
|
|
|
open: fn [^host], [{:port, ^port}, {:ssl, false} | _] ->
|
|
|
|
{:error, ~c"connect failed"}
|
|
|
|
end,
|
2020-06-27 17:12:45 +00:00
|
|
|
simple_bind: fn _connection, _dn, password ->
|
|
|
|
case password do
|
|
|
|
^admin_password -> :ok
|
|
|
|
^user_password -> :ok
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
equalityMatch: fn _type, _value -> :ok end,
|
|
|
|
wholeSubtree: fn -> :ok end,
|
|
|
|
search: fn _connection, _options ->
|
|
|
|
{:ok,
|
2023-08-17 11:18:01 +00:00
|
|
|
{:eldap_search_result, [{:eldap_entry, ~c"", [{~c"cn", [to_charlist("MyUser")]}]}],
|
|
|
|
[]}}
|
2020-06-27 17:12:45 +00:00
|
|
|
end,
|
|
|
|
close: fn _connection ->
|
|
|
|
send(self(), :close_connection)
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
]}
|
|
|
|
] do
|
|
|
|
log =
|
|
|
|
capture_log(fn ->
|
|
|
|
res =
|
|
|
|
conn
|
|
|
|
|> AbsintheHelpers.graphql_query(
|
|
|
|
query: @login_mutation,
|
|
|
|
variables: %{email: user.email, password: user_password}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert is_nil(res["error"])
|
|
|
|
assert token = res["data"]["login"]["accessToken"]
|
|
|
|
|
|
|
|
{:ok, %User{} = user_from_token, _claims} = Guardian.resource_from_token(token)
|
|
|
|
|
|
|
|
assert user_from_token.email == user.email
|
|
|
|
end)
|
|
|
|
|
|
|
|
assert log =~ "Could not open LDAP connection: 'connect failed'"
|
|
|
|
refute_received :close_connection
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@tag @skip
|
|
|
|
test "disallow authorization for wrong LDAP credentials", %{conn: conn} do
|
|
|
|
user_password = "testpassword"
|
|
|
|
user = insert(:user, password_hash: Argon2.hash_pwd_salt(user_password))
|
|
|
|
|
|
|
|
host = [:ldap, :host] |> Mobilizon.Config.get() |> to_charlist
|
|
|
|
port = Mobilizon.Config.get([:ldap, :port])
|
|
|
|
|
|
|
|
with_mocks [
|
|
|
|
{:eldap, [],
|
|
|
|
[
|
|
|
|
open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end,
|
|
|
|
simple_bind: fn _connection, _dn, _password -> {:error, :invalidCredentials} end,
|
|
|
|
close: fn _connection ->
|
|
|
|
send(self(), :close_connection)
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
]}
|
|
|
|
] do
|
|
|
|
res =
|
|
|
|
conn
|
|
|
|
|> AbsintheHelpers.graphql_query(
|
|
|
|
query: @login_mutation,
|
|
|
|
variables: %{email: user.email, password: user_password}
|
|
|
|
)
|
|
|
|
|
|
|
|
refute is_nil(res["errors"])
|
|
|
|
|
|
|
|
assert assert hd(res["errors"])["message"] ==
|
|
|
|
"Impossible to authenticate, either your email or password are invalid."
|
|
|
|
|
|
|
|
assert_received :close_connection
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "can change" do
|
|
|
|
test "password" do
|
|
|
|
assert LDAPAuthenticator.can_change_password?(%User{provider: "ldap"}) == false
|
|
|
|
assert LDAPAuthenticator.can_change_password?(%User{provider: nil}) == true
|
|
|
|
end
|
|
|
|
|
|
|
|
test "email" do
|
|
|
|
assert LDAPAuthenticator.can_change_password?(%User{provider: "ldap"}) == false
|
|
|
|
assert LDAPAuthenticator.can_change_password?(%User{provider: nil}) == true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|