mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
fix(portal): Prevent additional email identities per actor (#8888)
This is a UI-only change for now to serve as a stop-gap while we work to overhaul the identity domain model. Related: #6294
This commit is contained in:
@@ -8,13 +8,27 @@ defmodule Web.Actors.Show do
|
||||
def mount(%{"id" => id}, _session, socket) do
|
||||
with {:ok, actor} <-
|
||||
Actors.fetch_actor_by_id(id, socket.assigns.subject,
|
||||
preload: [:last_seen_at, groups: [:provider]]
|
||||
preload: [:identities, :last_seen_at, groups: [:provider]]
|
||||
) do
|
||||
:ok = Clients.subscribe_to_clients_presence_for_actor(actor)
|
||||
|
||||
available_providers =
|
||||
Auth.all_active_providers_for_account!(socket.assigns.account)
|
||||
|> Enum.filter(fn provider ->
|
||||
# TODO: This will be refactored to enforce with a DB constraint, but for now
|
||||
# we don't allow creating multiple identities per actor for the same provider.
|
||||
Enum.all?(actor.identities, fn identity ->
|
||||
identity.provider_id != provider.id
|
||||
end) and
|
||||
Auth.fetch_provider_capabilities!(provider)
|
||||
|> Keyword.fetch!(:provisioners)
|
||||
|> Enum.member?(:manual)
|
||||
end)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(
|
||||
available_providers: available_providers,
|
||||
page_title: "Actor #{actor.name}",
|
||||
flow_activities_enabled?: Accounts.flow_activities_enabled?(socket.assigns.account),
|
||||
actor: actor
|
||||
@@ -232,7 +246,7 @@ defmodule Web.Actors.Show do
|
||||
Each authentication identity is associated with an identity provider and is used to identify the actor upon successful authentication.
|
||||
</:help>
|
||||
|
||||
<:action :if={is_nil(@actor.deleted_at)}>
|
||||
<:action :if={is_nil(@actor.deleted_at) and Enum.any?(@available_providers)}>
|
||||
<.add_button
|
||||
:if={@actor.type != :service_account}
|
||||
navigate={~p"/#{@account}/actors/users/#{@actor}/new_identity"}
|
||||
@@ -664,8 +678,27 @@ defmodule Web.Actors.Show do
|
||||
{:ok, identity} = Auth.fetch_identity_by_id(id, socket.assigns.subject)
|
||||
{:ok, _identity} = Auth.delete_identity(identity, socket.assigns.subject)
|
||||
|
||||
{:ok, actor} =
|
||||
Actors.fetch_actor_by_id(socket.assigns.actor.id, socket.assigns.subject,
|
||||
preload: [:identities]
|
||||
)
|
||||
|
||||
available_providers =
|
||||
Auth.all_active_providers_for_account!(socket.assigns.account)
|
||||
|> Enum.filter(fn provider ->
|
||||
# TODO: This will be refactored to enforce with a DB constraint, but for now
|
||||
# we don't allow creating multiple identities per actor for the same provider.
|
||||
Enum.all?(actor.identities, fn identity ->
|
||||
identity.provider_id != provider.id
|
||||
end) and
|
||||
Auth.fetch_provider_capabilities!(provider)
|
||||
|> Keyword.fetch!(:provisioners)
|
||||
|> Enum.member?(:manual)
|
||||
end)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(actor: actor, available_providers: available_providers)
|
||||
|> reload_live_table!("identities")
|
||||
|> put_flash(:info, "Identity was deleted.")
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ defmodule Web.Actors.Users.NewIdentity do
|
||||
def mount(%{"id" => id} = params, _session, socket) do
|
||||
with {:ok, actor} <-
|
||||
Actors.fetch_actor_by_id(id, socket.assigns.subject,
|
||||
preload: [:memberships],
|
||||
preload: [:memberships, :identities],
|
||||
filter: [
|
||||
deleted?: false,
|
||||
types: ["account_user", "account_admin_user"]
|
||||
@@ -15,9 +15,14 @@ defmodule Web.Actors.Users.NewIdentity do
|
||||
providers =
|
||||
Auth.all_active_providers_for_account!(socket.assigns.account)
|
||||
|> Enum.filter(fn provider ->
|
||||
Auth.fetch_provider_capabilities!(provider)
|
||||
|> Keyword.fetch!(:provisioners)
|
||||
|> Enum.member?(:manual)
|
||||
# TODO: This will be refactored to enforce with a DB constraint, but for now
|
||||
# we don't allow creating multiple identities per actor for the same provider.
|
||||
Enum.all?(actor.identities, fn identity ->
|
||||
identity.provider_id != provider.id
|
||||
end) and
|
||||
Auth.fetch_provider_capabilities!(provider)
|
||||
|> Keyword.fetch!(:provisioners)
|
||||
|> Enum.member?(:manual)
|
||||
end)
|
||||
|
||||
provider = List.first(providers)
|
||||
|
||||
@@ -5,16 +5,22 @@ defmodule Web.Live.Actors.User.NewIdentityTest do
|
||||
Domain.Config.put_env_override(:outbound_email_adapter_configured?, true)
|
||||
|
||||
account = Fixtures.Accounts.create_account()
|
||||
provider = Fixtures.Auth.create_email_provider(account: account)
|
||||
_provider = Fixtures.Auth.create_email_provider(account: account)
|
||||
|
||||
# TODO: Users won't be able to naturally arrive at some of the routes tested on this page without another
|
||||
# manual provisioning provider like OIDC, so we add it here. Clean this up when identities are refactored.
|
||||
{oidc_provider, _bypass} =
|
||||
Fixtures.Auth.start_and_create_openid_connect_provider(account: account)
|
||||
|
||||
actor =
|
||||
Fixtures.Actors.create_actor(
|
||||
type: :account_admin_user,
|
||||
account: account,
|
||||
provider: provider
|
||||
provider: oidc_provider
|
||||
)
|
||||
|
||||
identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor)
|
||||
identity =
|
||||
Fixtures.Auth.create_identity(account: account, provider: oidc_provider, actor: actor)
|
||||
|
||||
%{
|
||||
account: account,
|
||||
|
||||
Reference in New Issue
Block a user