diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/ldap.ex | 78 | ||||
| -rw-r--r-- | lib/pleroma/web/auth/authenticator.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/web/auth/ldap_authenticator.ex | 9 | ||||
| -rw-r--r-- | lib/pleroma/web/auth/pleroma_authenticator.ex | 20 | ||||
| -rw-r--r-- | lib/pleroma/web/auth/wrapper_authenticator.ex | 4 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/controllers/util_controller.ex | 29 | 
6 files changed, 106 insertions, 39 deletions
diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex index 46a2d0c17..b591c2918 100644 --- a/lib/pleroma/ldap.ex +++ b/lib/pleroma/ldap.ex @@ -15,6 +15,14 @@ defmodule Pleroma.LDAP do      GenServer.start_link(__MODULE__, [], name: __MODULE__)    end +  def bind_user(name, password) do +    GenServer.call(__MODULE__, {:bind_user, name, password}) +  end + +  def change_password(name, password, new_password) do +    GenServer.call(__MODULE__, {:change_password, name, password, new_password}) +  end +    @impl true    def init(state) do      case {Config.get(Pleroma.Web.Auth.Authenticator), Config.get([:ldap, :enabled])} do @@ -47,33 +55,16 @@ defmodule Pleroma.LDAP do    def handle_info(:connect, _state), do: do_handle_connect()    def handle_info({:bind_after_reconnect, name, password, from}, state) do -    result = bind_user(state[:handle], name, password) +    result = do_bind_user(state[:handle], name, password)      GenServer.reply(from, result)      {:noreply, state}    end -  defp do_handle_connect do -    state = -      case connect() do -        {:ok, handle} -> -          :eldap.controlling_process(handle, self()) -          Process.link(handle) -          [handle: handle] - -        _ -> -          Logger.error("Failed to connect to LDAP. Retrying in 5000ms") -          Process.send_after(self(), :connect, 5_000) -          [] -      end - -    {:noreply, state} -  end -    @impl true    def handle_call({:bind_user, name, password}, from, state) do -    case bind_user(state[:handle], name, password) do +    case do_bind_user(state[:handle], name, password) do        :needs_reconnect ->          Process.send(self(), {:bind_after_reconnect, name, password, from}, [])          {:noreply, state, {:continue, :connect}} @@ -83,6 +74,12 @@ defmodule Pleroma.LDAP do      end    end +  def handle_call({:change_password, name, password, new_password}, _from, state) do +    result = change_password(state[:handle], name, password, new_password) + +    {:reply, result, state, :hibernate} +  end +    @impl true    def terminate(_, state) do      handle = Keyword.get(state, :handle) @@ -94,8 +91,21 @@ defmodule Pleroma.LDAP do      :ok    end -  def bind_user(name, password) do -    GenServer.call(__MODULE__, {:bind_user, name, password}) +  defp do_handle_connect do +    state = +      case connect() do +        {:ok, handle} -> +          :eldap.controlling_process(handle, self()) +          Process.link(handle) +          [handle: handle] + +        _ -> +          Logger.error("Failed to connect to LDAP. Retrying in 5000ms") +          Process.send_after(self(), :connect, 5_000) +          [] +      end + +    {:noreply, state}    end    defp connect do @@ -161,18 +171,17 @@ defmodule Pleroma.LDAP do      end    end -  defp bind_user(handle, name, password) do -    uid = Config.get([:ldap, :uid], "cn") -    base = Config.get([:ldap, :base]) +  defp do_bind_user(handle, name, password) do +    dn = make_dn(name) -    case :eldap.simple_bind(handle, "#{uid}=#{name},#{base}", password) do +    case :eldap.simple_bind(handle, dn, password) do        :ok ->          case fetch_user(name) do            %User{} = user ->              user            _ -> -            register_user(handle, base, uid, name) +            register_user(handle, ldap_base(), ldap_uid(), name)          end        # eldap does not inform us of socket closure @@ -231,6 +240,14 @@ defmodule Pleroma.LDAP do      end    end +  defp change_password(handle, name, password, new_password) do +    dn = make_dn(name) + +    with :ok <- :eldap.simple_bind(handle, dn, password) do +      :eldap.modify_password(handle, dn, to_charlist(new_password), to_charlist(password)) +    end +  end +    defp decode_certfile(file) do      with {:ok, data} <- File.read(file) do        data @@ -242,4 +259,13 @@ defmodule Pleroma.LDAP do          []      end    end + +  defp ldap_uid, do: to_charlist(Config.get([:ldap, :uid], "cn")) +  defp ldap_base, do: to_charlist(Config.get([:ldap, :base])) + +  defp make_dn(name) do +    uid = ldap_uid() +    base = ldap_base() +    ~c"#{uid}=#{name},#{base}" +  end  end diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex index 01bf1575c..95be892cd 100644 --- a/lib/pleroma/web/auth/authenticator.ex +++ b/lib/pleroma/web/auth/authenticator.ex @@ -10,4 +10,9 @@ defmodule Pleroma.Web.Auth.Authenticator do    @callback handle_error(Plug.Conn.t(), any()) :: any()    @callback auth_template() :: String.t() | nil    @callback oauth_consumer_template() :: String.t() | nil + +  @callback change_password(Pleroma.User.t(), String.t(), String.t(), String.t()) :: +              {:ok, Pleroma.User.t()} | {:error, term()} + +  @optional_callbacks change_password: 4  end diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex index 7eb06183d..ec6601fb9 100644 --- a/lib/pleroma/web/auth/ldap_authenticator.ex +++ b/lib/pleroma/web/auth/ldap_authenticator.ex @@ -30,4 +30,13 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do          error      end    end + +  def change_password(user, password, new_password, new_password) do +    case LDAP.change_password(user.nickname, password, new_password) do +      :ok -> {:ok, user} +      e -> e +    end +  end + +  def change_password(_, _, _, _), do: {:error, :password_confirmation}  end diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index 09a58eb66..0da3f19fc 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do    alias Pleroma.Registration    alias Pleroma.Repo    alias Pleroma.User +  alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Plugs.AuthenticationPlug    import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1] @@ -101,4 +102,23 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do    def auth_template, do: nil    def oauth_consumer_template, do: nil + +  @doc "Changes Pleroma.User password in the database" +  def change_password(user, password, new_password, new_password) do +    case CommonAPI.Utils.confirm_current_password(user, password) do +      {:ok, user} -> +        with {:ok, _user} <- +               User.reset_password(user, %{ +                 password: new_password, +                 password_confirmation: new_password +               }) do +          {:ok, user} +        end + +      error -> +        error +    end +  end + +  def change_password(_, _, _, _), do: {:error, :password_confirmation}  end diff --git a/lib/pleroma/web/auth/wrapper_authenticator.ex b/lib/pleroma/web/auth/wrapper_authenticator.ex index a077cfa41..97b901036 100644 --- a/lib/pleroma/web/auth/wrapper_authenticator.ex +++ b/lib/pleroma/web/auth/wrapper_authenticator.ex @@ -39,4 +39,8 @@ defmodule Pleroma.Web.Auth.WrapperAuthenticator do      implementation().oauth_consumer_template() ||        Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html")    end + +  @impl true +  def change_password(user, password, new_password, new_password_confirmation), +    do: implementation().change_password(user, password, new_password, new_password_confirmation)  end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 6805233df..aeafa195d 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -13,6 +13,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do    alias Pleroma.Healthcheck    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.Auth.WrapperAuthenticator, as: Authenticator    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Plugs.OAuthScopesPlug    alias Pleroma.Web.WebFinger @@ -195,19 +196,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do          %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: body_params}}} = conn,          _        ) do -    case CommonAPI.Utils.confirm_current_password(user, body_params.password) do -      {:ok, user} -> -        with {:ok, _user} <- -               User.reset_password(user, %{ -                 password: body_params.new_password, -                 password_confirmation: body_params.new_password_confirmation -               }) do -          json(conn, %{status: "success"}) -        else -          {:error, changeset} -> -            {_, {error, _}} = Enum.at(changeset.errors, 0) -            json(conn, %{error: "New password #{error}."}) -        end +    with {:ok, %User{}} <- +           Authenticator.change_password( +             user, +             body_params.password, +             body_params.new_password, +             body_params.new_password_confirmation +           ) do +      json(conn, %{status: "success"}) +    else +      {:error, %Ecto.Changeset{} = changeset} -> +        {_, {error, _}} = Enum.at(changeset.errors, 0) +        json(conn, %{error: "New password #{error}."}) + +      {:error, :password_confirmation} -> +        json(conn, %{error: "New password does not match confirmation."})        {:error, msg} ->          json(conn, %{error: msg})  | 
