diff options
| author | lambda <pleromagit@rogerbraun.net> | 2018-09-08 09:20:34 +0000 | 
|---|---|---|
| committer | lambda <pleromagit@rogerbraun.net> | 2018-09-08 09:20:34 +0000 | 
| commit | 045953225e04862c914b51808907cc86b11fcaf4 (patch) | |
| tree | 8f629e1572eec131651eae1a4421b6725b6f189a /lib | |
| parent | 530561a091f6f82e27ef3d5011b929b00e2da964 (diff) | |
| parent | d22af29bb48e94ca21621c30d46cea42559277b7 (diff) | |
| download | pleroma-045953225e04862c914b51808907cc86b11fcaf4.tar.gz pleroma-045953225e04862c914b51808907cc86b11fcaf4.zip  | |
Merge branch 'moonman/pleroma-sha512-crypt' into 'develop'
auth overhaul and legacy GS auth
See merge request pleroma/pleroma!331
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/plugs/authentication_plug.ex | 64 | ||||
| -rw-r--r-- | lib/pleroma/plugs/basic_auth_decoder_plug.ex | 21 | ||||
| -rw-r--r-- | lib/pleroma/plugs/ensure_authenticated_plug.ex | 19 | ||||
| -rw-r--r-- | lib/pleroma/plugs/ensure_user_key_plug.ex | 14 | ||||
| -rw-r--r-- | lib/pleroma/plugs/legacy_authentication_plug.ex | 35 | ||||
| -rw-r--r-- | lib/pleroma/plugs/session_authentication_plug.ex | 18 | ||||
| -rw-r--r-- | lib/pleroma/plugs/set_user_session_id_plug.ex | 15 | ||||
| -rw-r--r-- | lib/pleroma/plugs/user_enabled_plug.ex | 17 | ||||
| -rw-r--r-- | lib/pleroma/plugs/user_fetcher_plug.ex | 34 | ||||
| -rw-r--r-- | lib/pleroma/web/router.ex | 48 | 
10 files changed, 224 insertions, 61 deletions
diff --git a/lib/pleroma/plugs/authentication_plug.ex b/lib/pleroma/plugs/authentication_plug.ex index 86a514541..3ac301b97 100644 --- a/lib/pleroma/plugs/authentication_plug.ex +++ b/lib/pleroma/plugs/authentication_plug.ex @@ -9,54 +9,34 @@ defmodule Pleroma.Plugs.AuthenticationPlug do    def call(%{assigns: %{user: %User{}}} = conn, _), do: conn -  def call(conn, opts) do -    with {:ok, username, password} <- decode_header(conn), -         {:ok, user} <- opts[:fetcher].(username), -         false <- !!user.info["deactivated"], -         saved_user_id <- get_session(conn, :user_id), -         {:ok, verified_user} <- verify(user, password, saved_user_id) do +  def call( +        %{ +          assigns: %{ +            auth_user: %{password_hash: password_hash} = auth_user, +            auth_credentials: %{password: password} +          } +        } = conn, +        _ +      ) do +    if Pbkdf2.checkpw(password, password_hash) do        conn -      |> assign(:user, verified_user) -      |> put_session(:user_id, verified_user.id) +      |> assign(:user, auth_user)      else -      _ -> conn |> halt_or_continue(opts) +      conn      end    end -  # Short-circuit if we have a cookie with the id for the given user. -  defp verify(%{id: id} = user, _password, id) do -    {:ok, user} -  end - -  defp verify(nil, _password, _user_id) do +  def call( +        %{ +          assigns: %{ +            auth_credentials: %{password: password} +          } +        } = conn, +        _ +      ) do      Pbkdf2.dummy_checkpw() -    :error -  end - -  defp verify(user, password, _user_id) do -    if Pbkdf2.checkpw(password, user.password_hash) do -      {:ok, user} -    else -      :error -    end -  end - -  defp decode_header(conn) do -    with ["Basic " <> header] <- get_req_header(conn, "authorization"), -         {:ok, userinfo} <- Base.decode64(header), -         [username, password] <- String.split(userinfo, ":", parts: 2) do -      {:ok, username, password} -    end -  end - -  defp halt_or_continue(conn, %{optional: true}) do -    conn |> assign(:user, nil) -  end - -  defp halt_or_continue(conn, _) do      conn -    |> put_resp_content_type("application/json") -    |> send_resp(403, Jason.encode!(%{error: "Invalid credentials."})) -    |> halt    end + +  def call(conn, _), do: conn  end diff --git a/lib/pleroma/plugs/basic_auth_decoder_plug.ex b/lib/pleroma/plugs/basic_auth_decoder_plug.ex new file mode 100644 index 000000000..fc8fcee98 --- /dev/null +++ b/lib/pleroma/plugs/basic_auth_decoder_plug.ex @@ -0,0 +1,21 @@ +defmodule Pleroma.Plugs.BasicAuthDecoderPlug do +  import Plug.Conn + +  def init(options) do +    options +  end + +  def call(conn, opts) do +    with ["Basic " <> header] <- get_req_header(conn, "authorization"), +         {:ok, userinfo} <- Base.decode64(header), +         [username, password] <- String.split(userinfo, ":", parts: 2) do +      conn +      |> assign(:auth_credentials, %{ +        username: username, +        password: password +      }) +    else +      _ -> conn +    end +  end +end diff --git a/lib/pleroma/plugs/ensure_authenticated_plug.ex b/lib/pleroma/plugs/ensure_authenticated_plug.ex new file mode 100644 index 000000000..bca44eb2c --- /dev/null +++ b/lib/pleroma/plugs/ensure_authenticated_plug.ex @@ -0,0 +1,19 @@ +defmodule Pleroma.Plugs.EnsureAuthenticatedPlug do +  import Plug.Conn +  alias Pleroma.User + +  def init(options) do +    options +  end + +  def call(%{assigns: %{user: %User{}}} = conn, _) do +    conn +  end + +  def call(conn, _) do +    conn +    |> put_resp_content_type("application/json") +    |> send_resp(403, Jason.encode!(%{error: "Invalid credentials."})) +    |> halt +  end +end diff --git a/lib/pleroma/plugs/ensure_user_key_plug.ex b/lib/pleroma/plugs/ensure_user_key_plug.ex new file mode 100644 index 000000000..05a567757 --- /dev/null +++ b/lib/pleroma/plugs/ensure_user_key_plug.ex @@ -0,0 +1,14 @@ +defmodule Pleroma.Plugs.EnsureUserKeyPlug do +  import Plug.Conn + +  def init(opts) do +    opts +  end + +  def call(%{assigns: %{user: _}} = conn, _), do: conn + +  def call(conn, _) do +    conn +    |> assign(:user, nil) +  end +end diff --git a/lib/pleroma/plugs/legacy_authentication_plug.ex b/lib/pleroma/plugs/legacy_authentication_plug.ex new file mode 100644 index 000000000..d22c1a647 --- /dev/null +++ b/lib/pleroma/plugs/legacy_authentication_plug.ex @@ -0,0 +1,35 @@ +defmodule Pleroma.Plugs.LegacyAuthenticationPlug do +  import Plug.Conn +  alias Pleroma.User + +  def init(options) do +    options +  end + +  def call(%{assigns: %{user: %User{}}} = conn, _), do: conn + +  def call( +        %{ +          assigns: %{ +            auth_user: %{password_hash: "$6$" <> _ = password_hash} = auth_user, +            auth_credentials: %{password: password} +          } +        } = conn, +        _ +      ) do +    with ^password_hash <- :crypt.crypt(password, password_hash), +         {:ok, user} <- +           User.reset_password(auth_user, %{password: password, password_confirmation: password}) do +      conn +      |> assign(:auth_user, user) +      |> assign(:user, user) +    else +      _ -> +        conn +    end +  end + +  def call(conn, _) do +    conn +  end +end diff --git a/lib/pleroma/plugs/session_authentication_plug.ex b/lib/pleroma/plugs/session_authentication_plug.ex new file mode 100644 index 000000000..904a27952 --- /dev/null +++ b/lib/pleroma/plugs/session_authentication_plug.ex @@ -0,0 +1,18 @@ +defmodule Pleroma.Plugs.SessionAuthenticationPlug do +  import Plug.Conn +  alias Pleroma.User + +  def init(options) do +    options +  end + +  def call(conn, _) do +    with saved_user_id <- get_session(conn, :user_id), +         %{auth_user: %{id: ^saved_user_id}} <- conn.assigns do +      conn +      |> assign(:user, conn.assigns.auth_user) +    else +      _ -> conn +    end +  end +end diff --git a/lib/pleroma/plugs/set_user_session_id_plug.ex b/lib/pleroma/plugs/set_user_session_id_plug.ex new file mode 100644 index 000000000..adc0a42b5 --- /dev/null +++ b/lib/pleroma/plugs/set_user_session_id_plug.ex @@ -0,0 +1,15 @@ +defmodule Pleroma.Plugs.SetUserSessionIdPlug do +  import Plug.Conn +  alias Pleroma.User + +  def init(opts) do +    opts +  end + +  def call(%{assigns: %{user: %User{id: id}}} = conn, _) do +    conn +    |> put_session(:user_id, id) +  end + +  def call(conn, _), do: conn +end diff --git a/lib/pleroma/plugs/user_enabled_plug.ex b/lib/pleroma/plugs/user_enabled_plug.ex new file mode 100644 index 000000000..9c3285896 --- /dev/null +++ b/lib/pleroma/plugs/user_enabled_plug.ex @@ -0,0 +1,17 @@ +defmodule Pleroma.Plugs.UserEnabledPlug do +  import Plug.Conn +  alias Pleroma.User + +  def init(options) do +    options +  end + +  def call(%{assigns: %{user: %User{info: %{"deactivated" => true}}}} = conn, _) do +    conn +    |> assign(:user, nil) +  end + +  def call(conn, _) do +    conn +  end +end diff --git a/lib/pleroma/plugs/user_fetcher_plug.ex b/lib/pleroma/plugs/user_fetcher_plug.ex new file mode 100644 index 000000000..9cbaaf40a --- /dev/null +++ b/lib/pleroma/plugs/user_fetcher_plug.ex @@ -0,0 +1,34 @@ +defmodule Pleroma.Plugs.UserFetcherPlug do +  import Plug.Conn +  alias Pleroma.Repo +  alias Pleroma.User + +  def init(options) do +    options +  end + +  def call(conn, options) do +    with %{auth_credentials: %{username: username}} <- conn.assigns, +         {:ok, %User{} = user} <- user_fetcher(username) do +      conn +      |> assign(:auth_user, user) +    else +      _ -> conn +    end +  end + +  defp user_fetcher(username_or_email) do +    { +      :ok, +      cond do +        # First, try logging in as if it was a name +        user = Repo.get_by(User, %{nickname: username_or_email}) -> +          user + +        # If we get nil, we try using it as an email +        user = Repo.get_by(User, %{email: username_or_email}) -> +          user +      end +    } +  end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 9dcf44795..856679899 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -9,47 +9,57 @@ defmodule Pleroma.Web.Router do    @public Keyword.get(@instance, :public)    @registrations_open Keyword.get(@instance, :registrations_open) -  def user_fetcher(username_or_email) do -    { -      :ok, -      cond do -        # First, try logging in as if it was a name -        user = Repo.get_by(User, %{nickname: username_or_email}) -> -          user - -        # If we get nil, we try using it as an email -        user = Repo.get_by(User, %{email: username_or_email}) -> -          user -      end -    } -  end -    pipeline :api do      plug(:accepts, ["json"])      plug(:fetch_session)      plug(Pleroma.Plugs.OAuthPlug) -    plug(Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}) +    plug(Pleroma.Plugs.BasicAuthDecoderPlug) +    plug(Pleroma.Plugs.UserFetcherPlug) +    plug(Pleroma.Plugs.SessionAuthenticationPlug) +    plug(Pleroma.Plugs.LegacyAuthenticationPlug) +    plug(Pleroma.Plugs.AuthenticationPlug) +    plug(Pleroma.Plugs.UserEnabledPlug) +    plug(Pleroma.Plugs.SetUserSessionIdPlug) +    plug(Pleroma.Plugs.EnsureUserKeyPlug)    end    pipeline :authenticated_api do      plug(:accepts, ["json"])      plug(:fetch_session)      plug(Pleroma.Plugs.OAuthPlug) -    plug(Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1}) +    plug(Pleroma.Plugs.BasicAuthDecoderPlug) +    plug(Pleroma.Plugs.UserFetcherPlug) +    plug(Pleroma.Plugs.SessionAuthenticationPlug) +    plug(Pleroma.Plugs.LegacyAuthenticationPlug) +    plug(Pleroma.Plugs.AuthenticationPlug) +    plug(Pleroma.Plugs.UserEnabledPlug) +    plug(Pleroma.Plugs.SetUserSessionIdPlug) +    plug(Pleroma.Plugs.EnsureAuthenticatedPlug)    end    pipeline :mastodon_html do      plug(:accepts, ["html"])      plug(:fetch_session)      plug(Pleroma.Plugs.OAuthPlug) -    plug(Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}) +    plug(Pleroma.Plugs.BasicAuthDecoderPlug) +    plug(Pleroma.Plugs.UserFetcherPlug) +    plug(Pleroma.Plugs.SessionAuthenticationPlug) +    plug(Pleroma.Plugs.LegacyAuthenticationPlug) +    plug(Pleroma.Plugs.AuthenticationPlug) +    plug(Pleroma.Plugs.UserEnabledPlug) +    plug(Pleroma.Plugs.SetUserSessionIdPlug) +    plug(Pleroma.Plugs.EnsureUserKeyPlug)    end    pipeline :pleroma_html do      plug(:accepts, ["html"])      plug(:fetch_session)      plug(Pleroma.Plugs.OAuthPlug) -    plug(Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}) +    plug(Pleroma.Plugs.BasicAuthDecoderPlug) +    plug(Pleroma.Plugs.UserFetcherPlug) +    plug(Pleroma.Plugs.SessionAuthenticationPlug) +    plug(Pleroma.Plugs.AuthenticationPlug) +    plug(Pleroma.Plugs.EnsureUserKeyPlug)    end    pipeline :well_known do  | 
