fix(portal): Verify email token identity (#4977)

This commit is contained in:
Andrew Dryga
2024-05-13 10:03:50 -06:00
committed by GitHub
parent 26b181ef53
commit 3dc68c7355
4 changed files with 51 additions and 6 deletions

View File

@@ -100,18 +100,25 @@ defmodule Domain.Auth.Adapters.Email do
@impl true
def verify_secret(%Identity{} = identity, %Context{} = context, encoded_token) do
with {:ok, token} <- Tokens.use_token(encoded_token, %{context | type: :email}) do
with {:ok, token} <- Tokens.use_token(encoded_token, %{context | type: :email}),
true <- token.identity_id == identity.id do
{:ok, identity} =
Identity.Changeset.update_identity_provider_state(identity, %{
last_used_token_id: token.id
})
|> Repo.update()
Identity.Query.not_disabled()
|> Identity.Query.by_id(identity.id)
|> Repo.fetch_and_update(Identity.Query,
with: fn identity ->
Identity.Changeset.update_identity_provider_state(identity, %{
last_used_token_id: token.id
})
end
)
{:ok, _count} = Tokens.delete_all_tokens_by_type_and_assoc(:email, identity)
{:ok, identity, nil}
else
{:error, :invalid_or_expired_token} -> {:error, :invalid_secret}
false -> {:error, :invalid_secret}
end
end
end

View File

@@ -176,6 +176,22 @@ defmodule Domain.Auth.Adapters.EmailTest do
assert token.deleted_at
end
test "returns error when token belongs to a different identity", %{
account: account,
provider: provider,
identity: identity,
context: context
} do
other_identity = Fixtures.Auth.create_identity(account: account, provider: provider)
{:ok, other_identity} = request_sign_in_token(other_identity, context)
nonce = other_identity.provider_virtual_state.nonce
fragment = other_identity.provider_virtual_state.fragment
token = nonce <> fragment
assert verify_secret(identity, context, token) == {:error, :invalid_secret}
end
test "returns error when token is expired", %{
context: context,
identity: identity,

View File

@@ -2989,6 +2989,26 @@ defmodule Domain.AuthTest do
{:error, :unauthorized}
end
test "returns error when secret belongs to a different identity invalid", %{
account: account,
provider: provider,
user_agent: user_agent,
remote_ip: remote_ip
} do
nonce = "test_nonce_for_firezone"
context = %Auth.Context{type: :browser, user_agent: user_agent, remote_ip: remote_ip}
identity = Fixtures.Auth.create_identity(account: account, provider: provider)
{:ok, identity} = Domain.Auth.Adapters.Email.request_sign_in_token(identity, context)
identity2 = Fixtures.Auth.create_identity(account: account, provider: provider)
{:ok, identity2} = Domain.Auth.Adapters.Email.request_sign_in_token(identity2, context)
secret = identity2.provider_virtual_state.nonce <> identity2.provider_virtual_state.fragment
assert sign_in(provider, identity.provider_identifier, nonce, secret, context) ==
{:error, :unauthorized}
end
test "returns error when nonce is invalid", %{
account: account,
provider: provider,

View File

@@ -1,11 +1,13 @@
defmodule Firezone.MixProject do
use Mix.Project
@version "VERSION" |> File.read!() |> String.trim()
def project do
[
name: :firezone,
apps_path: "apps",
version: String.trim(File.read!("VERSION")),
version: @version,
start_permanent: Mix.env() == :prod,
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [