Add TOTP support in the invalidation session plug (#87)

This commit is contained in:
Dan Schultzer 2020-04-18 17:19:07 -07:00 committed by GitHub
parent 72f53d378d
commit 051a204d55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 3 deletions

View file

@ -87,9 +87,14 @@ defmodule PhilomenaWeb.PowInvalidatedSessionPlug do
defp maybe_put_cache(conn, user, old_token, opts) do defp maybe_put_cache(conn, user, old_token, opts) do
fetch_fn = Keyword.fetch!(opts, :fetch_token) fetch_fn = Keyword.fetch!(opts, :fetch_token)
metadata =
conn.private
|> Map.get(:pow_session_metadata, [])
|> Keyword.take([:valid_totp_at])
case fetch_fn.(conn) do case fetch_fn.(conn) do
^old_token -> conn ^old_token -> conn
_token -> put_cache(conn, user, old_token, opts) _token -> put_cache(conn, {user, metadata}, old_token, opts)
end end
end end
@ -106,8 +111,15 @@ defmodule PhilomenaWeb.PowInvalidatedSessionPlug do
{store, store_config} = invalidated_cache(conn, opts) {store, store_config} = invalidated_cache(conn, opts)
case store.get(store_config, token) do case store.get(store_config, token) do
:not_found -> conn :not_found ->
user -> Plug.assign_current_user(conn, user, config) conn
{user, metadata} ->
metadata = Keyword.merge(metadata, conn.private[:pow_session_metadata] || [])
conn
|> Conn.put_private(:pow_session_metadata, metadata)
|> Plug.assign_current_user(user, config)
end end
end end

View file

@ -43,12 +43,16 @@ defmodule PhilomenaWeb.PowInvalidatedSessionPlugTest do
assert Pow.Plug.current_user(conn).id == user.id assert Pow.Plug.current_user(conn).id == user.id
assert Conn.get_session(conn, @session_key) != session_id assert Conn.get_session(conn, @session_key) != session_id
assert metadata = conn.private[:pow_session_metadata]
refute metadata[:valid_totp_at]
:timer.sleep(100) :timer.sleep(100)
conn = run_plug(init_conn, config) conn = run_plug(init_conn, config)
assert Pow.Plug.current_user(conn).id == user.id assert Pow.Plug.current_user(conn).id == user.id
assert Conn.get_session(conn, @session_key) == session_id assert Conn.get_session(conn, @session_key) == session_id
assert metadata = conn.private[:pow_session_metadata]
refute metadata[:valid_totp_at]
:timer.sleep(@invalidated_ttl - 100) :timer.sleep(@invalidated_ttl - 100)
conn = run_plug(init_conn) conn = run_plug(init_conn)
@ -65,12 +69,16 @@ defmodule PhilomenaWeb.PowInvalidatedSessionPlugTest do
assert Pow.Plug.current_user(conn).id == user.id assert Pow.Plug.current_user(conn).id == user.id
assert conn.cookies[@cookie_key] != persistent_session_id assert conn.cookies[@cookie_key] != persistent_session_id
assert metadata = conn.private[:pow_session_metadata]
refute metadata[:valid_totp_at]
:timer.sleep(100) :timer.sleep(100)
conn = run_plug(init_conn) conn = run_plug(init_conn)
assert Pow.Plug.current_user(conn).id == user.id assert Pow.Plug.current_user(conn).id == user.id
assert conn.cookies[@cookie_key] == persistent_session_id assert conn.cookies[@cookie_key] == persistent_session_id
assert metadata = conn.private[:pow_session_metadata]
refute metadata[:valid_totp_at]
:timer.sleep(@invalidated_ttl - 100) :timer.sleep(@invalidated_ttl - 100)
conn = run_plug(init_conn) conn = run_plug(init_conn)
@ -79,6 +87,42 @@ defmodule PhilomenaWeb.PowInvalidatedSessionPlugTest do
assert conn.cookies[@cookie_key] == persistent_session_id assert conn.cookies[@cookie_key] == persistent_session_id
end end
test "call/2 with TOTP turned on", %{conn: init_conn, user: user} do
user =
user
|> Ecto.Changeset.change(%{otp_required_for_login: true})
|> Repo.update!()
config = Keyword.put(@config, :session_ttl_renewal, 0)
no_otp_auth_conn =
init_conn
|> prepare_session_conn(user, config)
|> init_plug(config)
assert no_otp_auth_conn.halted
init_conn =
init_conn
|> Conn.put_private(:pow_session_metadata, valid_totp_at: DateTime.utc_now())
|> prepare_session_conn(user, config)
conn = run_plug(init_conn, config)
assert Pow.Plug.current_user(conn).id == user.id
assert metadata = conn.private[:pow_session_metadata]
assert metadata[:valid_totp_at]
assert metadata[:inserted_at]
:timer.sleep(100)
conn = run_plug(init_conn, config)
assert Pow.Plug.current_user(conn).id == user.id
assert metadata = conn.private[:pow_session_metadata]
assert metadata[:valid_totp_at]
refute metadata[:inserted_at]
end
defp init_session_plug(conn) do defp init_session_plug(conn) do
conn conn
|> Map.put(:secret_key_base, String.duplicate("abcdefghijklmnopqrstuvxyz0123456789", 2)) |> Map.put(:secret_key_base, String.duplicate("abcdefghijklmnopqrstuvxyz0123456789", 2))
@ -97,6 +141,7 @@ defmodule PhilomenaWeb.PowInvalidatedSessionPlugTest do
|> Session.call(Session.init(config)) |> Session.call(Session.init(config))
|> Cookie.call(Cookie.init([])) |> Cookie.call(Cookie.init([]))
|> PowInvalidatedSessionPlug.call(PowInvalidatedSessionPlug.init(:load)) |> PowInvalidatedSessionPlug.call(PowInvalidatedSessionPlug.init(:load))
|> PhilomenaWeb.TotpPlug.call(PhilomenaWeb.TotpPlug.init([]))
end end
defp run_plug(conn, config \\ @config) do defp run_plug(conn, config \\ @config) do