purge ldap authenticator (#92)
authorfloatingghost <hannah@coffee-and-dreams.uk>
Wed, 20 Jul 2022 12:49:13 +0000 (12:49 +0000)
committerfloatingghost <hannah@coffee-and-dreams.uk>
Wed, 20 Jul 2022 12:49:13 +0000 (12:49 +0000)
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/92

CHANGELOG.md
config/config.exs
config/description.exs
docs/docs/configuration/cheatsheet.md
docs/docs/installation/alpine_linux_en.md
lib/pleroma/user.ex
lib/pleroma/web/auth/ldap_authenticator.ex [deleted file]
mix.exs
test/pleroma/web/o_auth/ldap_authorization_test.exs [deleted file]

index 3fe07f2902fe3b9286f93247dc60c7989cee32b5..8546370e97e2f1b29ff9b8e339bf50c5cb5f65e7 100644 (file)
@@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
   - `/api/v1/notifications/dismiss`
   - `/api/v1/search`
   - `/api/v1/statuses/{id}/card` 
+- LDAP authenticator
 
 ## 2022.07
 
index 9186b011d40f146ca43e56195539c6cd46db0710..61b5a0317e31bbf3b85efaa0706ad252e4c9d4fc 100644 (file)
@@ -511,6 +511,7 @@ config :pleroma, Pleroma.User,
     "~",
     "about",
     "activities",
+    "akkoma",
     "api",
     "auth",
     "check_password",
@@ -591,17 +592,6 @@ config :pleroma, Pleroma.Formatter,
   extra: true,
   validate_tld: :no_scheme
 
-config :pleroma, :ldap,
-  enabled: System.get_env("LDAP_ENABLED") == "true",
-  host: System.get_env("LDAP_HOST") || "localhost",
-  port: String.to_integer(System.get_env("LDAP_PORT") || "389"),
-  ssl: System.get_env("LDAP_SSL") == "true",
-  sslopts: [],
-  tls: System.get_env("LDAP_TLS") == "true",
-  tlsopts: [],
-  base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
-  uid: System.get_env("LDAP_UID") || "cn"
-
 oauth_consumer_strategies =
   "OAUTH_CONSUMER_STRATEGIES"
   |> System.get_env()
index 098a6f5b72d35af2cf77ce86d9327354310ccf4b..c67da64b532f16ee79c56cee1d0821cd098e8b7f 100644 (file)
@@ -2158,104 +2158,6 @@ config :pleroma, :config_description, [
       }
     ]
   },
-  %{
-    group: :pleroma,
-    key: :ldap,
-    label: "LDAP",
-    type: :group,
-    description:
-      "Use LDAP for user authentication. When a user logs in to the Pleroma instance, the name and password" <>
-        " will be verified by trying to authenticate (bind) to a LDAP server." <>
-        " If a user exists in the LDAP directory but there is no account with the same name yet on the" <>
-        " Pleroma instance then a new Pleroma account will be created with the same name as the LDAP user name.",
-    children: [
-      %{
-        key: :enabled,
-        type: :boolean,
-        description: "Enables LDAP authentication"
-      },
-      %{
-        key: :host,
-        type: :string,
-        description: "LDAP server hostname",
-        suggestions: ["localhosts"]
-      },
-      %{
-        key: :port,
-        type: :integer,
-        description: "LDAP port, e.g. 389 or 636",
-        suggestions: [389, 636]
-      },
-      %{
-        key: :ssl,
-        label: "SSL",
-        type: :boolean,
-        description: "Enable to use SSL, usually implies the port 636"
-      },
-      %{
-        key: :sslopts,
-        label: "SSL options",
-        type: :keyword,
-        description: "Additional SSL options",
-        suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
-        children: [
-          %{
-            key: :cacertfile,
-            type: :string,
-            description: "Path to file with PEM encoded cacerts",
-            suggestions: ["path/to/file/with/PEM/cacerts"]
-          },
-          %{
-            key: :verify,
-            type: :atom,
-            description: "Type of cert verification",
-            suggestions: [:verify_peer]
-          }
-        ]
-      },
-      %{
-        key: :tls,
-        label: "TLS",
-        type: :boolean,
-        description: "Enable to use STARTTLS, usually implies the port 389"
-      },
-      %{
-        key: :tlsopts,
-        label: "TLS options",
-        type: :keyword,
-        description: "Additional TLS options",
-        suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
-        children: [
-          %{
-            key: :cacertfile,
-            type: :string,
-            description: "Path to file with PEM encoded cacerts",
-            suggestions: ["path/to/file/with/PEM/cacerts"]
-          },
-          %{
-            key: :verify,
-            type: :atom,
-            description: "Type of cert verification",
-            suggestions: [:verify_peer]
-          }
-        ]
-      },
-      %{
-        key: :base,
-        type: :string,
-        description: "LDAP base, e.g. \"dc=example,dc=com\"",
-        suggestions: ["dc=example,dc=com"]
-      },
-      %{
-        key: :uid,
-        label: "UID",
-        type: :string,
-        description:
-          "LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter will be \"cn=username,base\"",
-        suggestions: ["cn"]
-      }
-    ]
-  },
   %{
     group: :pleroma,
     key: :auth,
index c7df00190498f35e40b9620e7ca1bc381fca2f96..85381d67c0a0fa4a799a12b6015ea3620c870151 100644 (file)
@@ -900,28 +900,6 @@ Authentication / authorization settings.
 ### Pleroma.Web.Auth.Authenticator
 
 * `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator.
-* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication.
-
-### :ldap
-
-Use LDAP for user authentication.  When a user logs in to the Akkoma
-instance, the name and password will be verified by trying to authenticate
-(bind) to an LDAP server.  If a user exists in the LDAP directory but there
-is no account with the same name yet on the Akkoma instance then a new
-Akkoma account will be created with the same name as the LDAP user name.
-
-* `enabled`: enables LDAP authentication
-* `host`: LDAP server hostname
-* `port`: LDAP port, e.g. 389 or 636
-* `ssl`: true to use SSL, usually implies the port 636
-* `sslopts`: additional SSL options
-* `tls`: true to start TLS, usually implies the port 389
-* `tlsopts`: additional TLS options
-* `base`: LDAP base, e.g. "dc=example,dc=com"
-* `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base"
-
-Note, if your LDAP server is an Active Directory server the correct value is commonly `uid: "cn"`, but if you use an
-OpenLDAP server the value may be `uid: "uid"`.
 
 ### :oauth2 (Akkoma as OAuth 2.0 provider settings)
 
index f98998fb8cdf828594fc83cf6289eefd63210f44..3be69af6ef9b8c45d9adb19c611b7c7daaca5042 100644 (file)
@@ -41,12 +41,6 @@ doas apk add git build-base cmake file-dev
 doas apk add erlang elixir
 ```
 
-* Install `erlang-eldap` if you want to enable ldap authenticator
-
-```shell
-doas apk add erlang-eldap
-```
-
 ### Install PostgreSQL
 
 * Install Postgresql server:
index a9caec55269cd69f864b72b658c25c8b650b4253..9ff52c94f2159d79acd1cf8c42ce55686a28fe63 100644 (file)
@@ -663,34 +663,6 @@ defmodule Pleroma.User do
   @spec force_password_reset(User.t()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
   def force_password_reset(user), do: update_password_reset_pending(user, true)
 
-  # Used to auto-register LDAP accounts which won't have a password hash stored locally
-  def register_changeset_ldap(struct, params = %{password: password})
-      when is_nil(password) do
-    params = Map.put_new(params, :accepts_chat_messages, true)
-
-    params =
-      if Map.has_key?(params, :email) do
-        Map.put_new(params, :email, params[:email])
-      else
-        params
-      end
-
-    struct
-    |> cast(params, [
-      :name,
-      :nickname,
-      :email,
-      :accepts_chat_messages
-    ])
-    |> validate_required([:name, :nickname])
-    |> unique_constraint(:nickname)
-    |> validate_exclusion(:nickname, Config.get([User, :restricted_nicknames]))
-    |> validate_format(:nickname, local_nickname_regex())
-    |> put_ap_id()
-    |> unique_constraint(:ap_id)
-    |> put_following_and_follower_and_featured_address()
-  end
-
   def register_changeset(struct, params \\ %{}, opts \\ []) do
     bio_limit = Config.get([:instance, :user_bio_length], 5000)
     name_limit = Config.get([:instance, :user_name_length], 100)
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
deleted file mode 100644 (file)
index f77e8d2..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.Auth.LDAPAuthenticator do
-  alias Pleroma.User
-
-  require Logger
-
-  import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1]
-
-  @behaviour Pleroma.Web.Auth.Authenticator
-  @base Pleroma.Web.Auth.PleromaAuthenticator
-
-  @connection_timeout 10_000
-  @search_timeout 10_000
-
-  defdelegate get_registration(conn), to: @base
-  defdelegate create_from_registration(conn, registration), to: @base
-  defdelegate handle_error(conn, error), to: @base
-  defdelegate auth_template, to: @base
-  defdelegate oauth_consumer_template, to: @base
-
-  def get_user(%Plug.Conn{} = conn) do
-    with {:ldap, true} <- {:ldap, Pleroma.Config.get([:ldap, :enabled])},
-         {:ok, {name, password}} <- fetch_credentials(conn),
-         %User{} = user <- ldap_user(name, password) do
-      {:ok, user}
-    else
-      {:ldap, _} ->
-        @base.get_user(conn)
-
-      error ->
-        error
-    end
-  end
-
-  defp ldap_user(name, password) do
-    ldap = Pleroma.Config.get(:ldap, [])
-    host = Keyword.get(ldap, :host, "localhost")
-    port = Keyword.get(ldap, :port, 389)
-    ssl = Keyword.get(ldap, :ssl, false)
-    sslopts = Keyword.get(ldap, :sslopts, [])
-
-    options =
-      [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}] ++
-        if sslopts != [], do: [{:sslopts, sslopts}], else: []
-
-    case :eldap.open([to_charlist(host)], options) do
-      {:ok, connection} ->
-        try do
-          if Keyword.get(ldap, :tls, false) do
-            :application.ensure_all_started(:ssl)
-
-            case :eldap.start_tls(
-                   connection,
-                   Keyword.get(ldap, :tlsopts, []),
-                   @connection_timeout
-                 ) do
-              :ok ->
-                :ok
-
-              error ->
-                Logger.error("Could not start TLS: #{inspect(error)}")
-            end
-          end
-
-          bind_user(connection, ldap, name, password)
-        after
-          :eldap.close(connection)
-        end
-
-      {:error, error} ->
-        Logger.error("Could not open LDAP connection: #{inspect(error)}")
-        {:error, {:ldap_connection_error, error}}
-    end
-  end
-
-  defp bind_user(connection, ldap, name, password) do
-    uid = Keyword.get(ldap, :uid, "cn")
-    base = Keyword.get(ldap, :base)
-
-    case :eldap.simple_bind(connection, "#{uid}=#{name},#{base}", password) do
-      :ok ->
-        case fetch_user(name) do
-          %User{} = user ->
-            user
-
-          _ ->
-            register_user(connection, base, uid, name)
-        end
-
-      error ->
-        error
-    end
-  end
-
-  defp register_user(connection, base, uid, name) do
-    case :eldap.search(connection, [
-           {:base, to_charlist(base)},
-           {:filter, :eldap.equalityMatch(to_charlist(uid), to_charlist(name))},
-           {:scope, :eldap.wholeSubtree()},
-           {:timeout, @search_timeout}
-         ]) do
-      {:ok, {:eldap_search_result, [{:eldap_entry, _, attributes}], _}} ->
-        params = %{
-          name: name,
-          nickname: name,
-          password: nil
-        }
-
-        params =
-          case List.keyfind(attributes, 'mail', 0) do
-            {_, [mail]} -> Map.put_new(params, :email, :erlang.list_to_binary(mail))
-            _ -> params
-          end
-
-        changeset = User.register_changeset_ldap(%User{}, params)
-
-        case User.register(changeset) do
-          {:ok, user} -> user
-          error -> error
-        end
-
-      error ->
-        error
-    end
-  end
-end
diff --git a/mix.exs b/mix.exs
index 420ea2e243e87028f755c64bd4d49abf79c64f54..a0eef4f1decc66e0eaa284a79724253dc58bf682 100644 (file)
--- a/mix.exs
+++ b/mix.exs
@@ -9,7 +9,6 @@ defmodule Pleroma.Mixfile do
       elixirc_paths: elixirc_paths(Mix.env()),
       compilers: [:phoenix, :gettext] ++ Mix.compilers(),
       elixirc_options: [warnings_as_errors: warnings_as_errors()],
-      xref: [exclude: [:eldap]],
       start_permanent: Mix.env() == :prod,
       aliases: aliases(),
       deps: deps(),
@@ -35,7 +34,7 @@ defmodule Pleroma.Mixfile do
       releases: [
         pleroma: [
           include_executables_for: [:unix],
-          applications: [ex_syslogger: :load, syslog: :load, eldap: :transient],
+          applications: [ex_syslogger: :load, syslog: :load],
           steps: [:assemble, &put_otp_version/1, &copy_files/1, &copy_nginx_config/1],
           config_providers: [{Pleroma.Config.ReleaseRuntimeProvider, []}]
         ]
diff --git a/test/pleroma/web/o_auth/ldap_authorization_test.exs b/test/pleroma/web/o_auth/ldap_authorization_test.exs
deleted file mode 100644 (file)
index 61b9ce6..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
-  use Pleroma.Web.ConnCase
-  alias Pleroma.Repo
-  alias Pleroma.Web.OAuth.Token
-  import Pleroma.Factory
-  import Mock
-
-  @skip if !Code.ensure_loaded?(:eldap), do: :skip
-
-  setup_all do: clear_config([:ldap, :enabled], true)
-
-  setup_all do: clear_config(Pleroma.Web.Auth.Authenticator, Pleroma.Web.Auth.LDAPAuthenticator)
-
-  @tag @skip
-  test "authorizes the existing user using LDAP credentials" do
-    password = "testpassword"
-    user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
-    app = insert(:oauth_app, scopes: ["read", "write"])
-
-    host = Pleroma.Config.get([:ldap, :host]) |> to_charlist
-    port = Pleroma.Config.get([:ldap, :port])
-
-    with_mocks [
-      {:eldap, [],
-       [
-         open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end,
-         simple_bind: fn _connection, _dn, ^password -> :ok end,
-         close: fn _connection ->
-           send(self(), :close_connection)
-           :ok
-         end
-       ]}
-    ] do
-      conn =
-        build_conn()
-        |> post("/oauth/token", %{
-          "grant_type" => "password",
-          "username" => user.nickname,
-          "password" => password,
-          "client_id" => app.client_id,
-          "client_secret" => app.client_secret
-        })
-
-      assert %{"access_token" => token} = json_response(conn, 200)
-
-      token = Repo.get_by(Token, token: token)
-
-      assert token.user_id == user.id
-      assert_received :close_connection
-    end
-  end
-
-  @tag @skip
-  test "creates a new user after successful LDAP authorization" do
-    password = "testpassword"
-    user = build(:user)
-    app = insert(:oauth_app, scopes: ["read", "write"])
-
-    host = Pleroma.Config.get([:ldap, :host]) |> to_charlist
-    port = Pleroma.Config.get([:ldap, :port])
-
-    with_mocks [
-      {:eldap, [],
-       [
-         open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end,
-         simple_bind: fn _connection, _dn, ^password -> :ok end,
-         equalityMatch: fn _type, _value -> :ok end,
-         wholeSubtree: fn -> :ok end,
-         search: fn _connection, _options ->
-           {:ok, {:eldap_search_result, [{:eldap_entry, '', []}], []}}
-         end,
-         close: fn _connection ->
-           send(self(), :close_connection)
-           :ok
-         end
-       ]}
-    ] do
-      conn =
-        build_conn()
-        |> post("/oauth/token", %{
-          "grant_type" => "password",
-          "username" => user.nickname,
-          "password" => password,
-          "client_id" => app.client_id,
-          "client_secret" => app.client_secret
-        })
-
-      assert %{"access_token" => token} = json_response(conn, 200)
-
-      token = Repo.get_by(Token, token: token) |> Repo.preload(:user)
-
-      assert token.user.nickname == user.nickname
-      assert_received :close_connection
-    end
-  end
-
-  @tag @skip
-  test "disallow authorization for wrong LDAP credentials" do
-    password = "testpassword"
-    user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
-    app = insert(:oauth_app, scopes: ["read", "write"])
-
-    host = Pleroma.Config.get([:ldap, :host]) |> to_charlist
-    port = Pleroma.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
-      conn =
-        build_conn()
-        |> post("/oauth/token", %{
-          "grant_type" => "password",
-          "username" => user.nickname,
-          "password" => password,
-          "client_id" => app.client_id,
-          "client_secret" => app.client_secret
-        })
-
-      assert %{"error" => "Invalid credentials"} = json_response(conn, 400)
-      assert_received :close_connection
-    end
-  end
-end