mirror of
https://github.com/team-alembic/ash_authentication.git
synced 2024-09-19 21:03:23 +12:00
fix: don't allow special purpose tokens to be used for sign in. (#191)
This fixes a security issue where someone in possession of a special purpose token (reset, confirmation, magic link, etc) would be able to access an API using this token. We strongly encourage you to upgrade. Closes #190.
This commit is contained in:
parent
3413ef8d6f
commit
ca3dac3878
3 changed files with 42 additions and 3 deletions
|
@ -75,7 +75,8 @@ defmodule AshAuthentication.Plug.Helpers do
|
|||
|
||||
with token when is_binary(token) <-
|
||||
Conn.get_session(conn, "#{options.subject_name}_token"),
|
||||
{:ok, %{"sub" => subject, "jti" => jti}, _} <- Jwt.verify(token, otp_app),
|
||||
{:ok, %{"sub" => subject, "jti" => jti} = claims, _}
|
||||
when not is_map_key(claims, "act") <- Jwt.verify(token, otp_app),
|
||||
{:ok, [_]} <-
|
||||
TokenResource.Actions.get_token(token_resource, %{
|
||||
"jti" => jti,
|
||||
|
@ -116,7 +117,8 @@ defmodule AshAuthentication.Plug.Helpers do
|
|||
|> Stream.filter(&String.starts_with?(&1, "Bearer "))
|
||||
|> Stream.map(&String.replace_leading(&1, "Bearer ", ""))
|
||||
|> Enum.reduce(conn, fn token, conn ->
|
||||
with {:ok, %{"sub" => subject, "jti" => jti}, resource} <- Jwt.verify(token, otp_app),
|
||||
with {:ok, %{"sub" => subject, "jti" => jti} = claims, resource}
|
||||
when not is_map_key(claims, "act") <- Jwt.verify(token, otp_app),
|
||||
:ok <- validate_token(resource, jti),
|
||||
{:ok, user} <- AshAuthentication.subject_to_user(subject, resource),
|
||||
{:ok, subject_name} <- Info.authentication_subject_name(resource),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
defmodule AshAuthentication.Plug.HelpersTest do
|
||||
@moduledoc false
|
||||
use DataCase, async: true
|
||||
alias AshAuthentication.{Jwt, Plug.Helpers, TokenResource}
|
||||
alias AshAuthentication.{Info, Jwt, Plug.Helpers, Strategy.Password, TokenResource}
|
||||
import Plug.Test, only: [conn: 3]
|
||||
alias Plug.Conn
|
||||
|
||||
|
@ -106,6 +106,20 @@ defmodule AshAuthentication.Plug.HelpersTest do
|
|||
|
||||
refute conn.assigns.current_user_with_token_required
|
||||
end
|
||||
|
||||
test "when the token is for another purpose it can't be used for sign in", %{conn: conn} do
|
||||
user = build_user_with_token_required()
|
||||
|
||||
strategy = Info.strategy!(user.__struct__, :password)
|
||||
{:ok, reset_token} = Password.reset_token_for(strategy, user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> Conn.put_session("user_with_token_required_token", reset_token)
|
||||
|> Helpers.retrieve_from_session(:ash_authentication)
|
||||
|
||||
refute conn.assigns.current_user_with_token_required
|
||||
end
|
||||
end
|
||||
|
||||
describe "retrieve_from_bearer/2" do
|
||||
|
@ -163,6 +177,20 @@ defmodule AshAuthentication.Plug.HelpersTest do
|
|||
|
||||
refute is_map_key(conn.assigns, :current_user_with_token_required)
|
||||
end
|
||||
|
||||
test "when the token is for another purpose, it doesn't let them sign in", %{conn: conn} do
|
||||
user = build_user()
|
||||
|
||||
strategy = Info.strategy!(user.__struct__, :password)
|
||||
{:ok, reset_token} = Password.reset_token_for(strategy, user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> Conn.put_req_header("authorization", "Bearer #{reset_token}")
|
||||
|> Helpers.retrieve_from_bearer(:ash_authentication)
|
||||
|
||||
refute is_map_key(conn.assigns, :current_user_with_token_required)
|
||||
end
|
||||
end
|
||||
|
||||
describe "revoke_bearer_tokens/2" do
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule Example.UserWithTokenRequired do
|
||||
@moduledoc false
|
||||
use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication]
|
||||
require Logger
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
id: Ecto.UUID.t(),
|
||||
|
@ -32,6 +33,14 @@ defmodule Example.UserWithTokenRequired do
|
|||
strategies do
|
||||
password do
|
||||
identity_field :email
|
||||
|
||||
resettable do
|
||||
sender fn user, token, _opts ->
|
||||
Logger.debug(
|
||||
"Password reset request for user #{user.username}, token #{inspect(token)}"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue