- <.form id="identity-provider-type-form" for={%{}} phx-submit="submit">
-
-
+
+
+
+ <%= for {adapter, opts} <- @adapters, opts[:sync] == true do %>
+ <.provider_card adapter={adapter} opts={opts} account={@account} />
+ <% end %>
+ <%= for {adapter, opts} <- @adapters, opts[:sync] == false do %>
+ <.provider_card adapter={adapter} opts={opts} account={@account} />
+ <% end %>
- <.submit_button>
- Next: Configure
-
-
+
"""
end
- def adapter(%{adapter: :google_workspace} = assigns) do
- ~H"""
- <.adapter_item
- adapter={@adapter}
- account={@account}
- opts={@opts}
- name="Google Workspace"
- description="Authenticate users and synchronize users and groups with a custom Google Workspace connector."
- />
- """
- end
-
- def adapter(%{adapter: :microsoft_entra} = assigns) do
- ~H"""
- <.adapter_item
- adapter={@adapter}
- account={@account}
- opts={@opts}
- name="Microsoft Entra"
- description="Authenticate users and synchronize users and groups with a custom Microsoft Entra ID connector."
- />
- """
- end
-
- def adapter(%{adapter: :okta} = assigns) do
- ~H"""
- <.adapter_item
- adapter={@adapter}
- account={@account}
- opts={@opts}
- name="Okta"
- description="Authenticate users and synchronize users and groups with a custom Okta connector."
- />
- """
- end
-
- def adapter(%{adapter: :openid_connect} = assigns) do
- ~H"""
- <.adapter_item
- adapter={@adapter}
- account={@account}
- opts={@opts}
- name="OpenID Connect"
- description="Authenticate users with a universal OpenID Connect adapter and manager users and groups manually."
- />
- """
- end
-
attr :adapter, :any
attr :account, :any
attr :opts, :any
- attr :name, :string
- attr :description, :string
- def adapter_item(assigns) do
+ def provider_card(assigns) do
~H"""
-
-
-
- <.provider_icon adapter={@adapter} class="w-8 h-8 ml-4" />
-
-
- <%= if @opts[:enabled] == false do %>
- <.link navigate={~p"/#{@account}/settings/billing"} class="ml-2 text-sm text-primary-500">
- <.badge class="ml-2" type="primary" title="Feature available on a higher pricing plan">
- <.icon name="hero-lock-closed" class="w-3.5 h-3.5 mr-1" /> UPGRADE TO UNLOCK
-
-
- <% end %>
+
+
+ <.provider_icon adapter={@adapter} class="w-10 h-10 inline-block mr-2" />
+ <%= pretty_print_provider(@adapter) %>
+
+
+
+ <.icon name="hero-arrow-path" class="w-5 h-5 text-neutral-400" />
-
- <%= @description %>
-
"""
end
- def next_step_path(:openid_connect, account) do
+ def next_step_path("openid_connect", account) do
~p"/#{account}/settings/identity_providers/openid_connect/new"
end
- def next_step_path(:google_workspace, account) do
- ~p"/#{account}/settings/identity_providers/google_workspace/new"
+ def next_step_path("google_workspace" = provider, account) do
+ if Domain.Accounts.idp_sync_enabled?(account) do
+ ~p"/#{account}/settings/identity_providers/google_workspace/new"
+ else
+ ~p"/#{account}/settings/identity_providers/openid_connect/new?provider=#{provider}"
+ end
end
- def next_step_path(:microsoft_entra, account) do
- ~p"/#{account}/settings/identity_providers/microsoft_entra/new"
+ def next_step_path("microsoft_entra" = provider, account) do
+ if Domain.Accounts.idp_sync_enabled?(account) do
+ ~p"/#{account}/settings/identity_providers/microsoft_entra/new"
+ else
+ ~p"/#{account}/settings/identity_providers/openid_connect/new?provider=#{provider}"
+ end
end
- def next_step_path(:okta, account) do
- ~p"/#{account}/settings/identity_providers/okta/new"
+ def next_step_path("okta" = provider, account) do
+ if Domain.Accounts.idp_sync_enabled?(account) do
+ ~p"/#{account}/settings/identity_providers/okta/new"
+ else
+ ~p"/#{account}/settings/identity_providers/openid_connect/new?provider=#{provider}"
+ end
+ end
+
+ def pretty_print_provider(adapter) do
+ case adapter do
+ :openid_connect -> "OpenID Connect"
+ :google_workspace -> "Google Workspace"
+ :microsoft_entra -> "Microsoft EntraID"
+ :okta -> "Okta"
+ end
end
end
diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/components.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/components.ex
index 8974a1f98..25d6bba6e 100644
--- a/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/components.ex
+++ b/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/components.ex
@@ -1,6 +1,11 @@
defmodule Web.Settings.IdentityProviders.OpenIDConnect.Components do
use Web, :component_library
+ attr :id, :string
+ attr :account, :any
+ attr :form, :any
+ attr :show_sync_msg, :boolean, default: false
+
def provider_form(assigns) do
~H"""
@@ -95,12 +100,47 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Components do
-
- <.submit_button>
- Connect Identity Provider
-
+ <.step :if={@show_sync_msg}>
+ <:title>
+ Step 3. Enable Directory Sync <.icon name="hero-arrow-path" class="w-5 h-5 ml-2" />
+
+ <.link
+ navigate={~p"/#{@account}/settings/billing"}
+ class="text-sm text-primary-500 ml-2"
+ >
+ <.badge type="primary" title="Feature available on a higher pricing plan">
+ <.icon name="hero-lock-closed" class="w-3.5 h-3.5 mr-1" /> UPGRADE TO UNLOCK
+
+
+
+
+ <:content>
+ Directory sync is not enabled on your current plan.
+
+
+ Ensure the following scopes are added to the OAuth application:
+
+ <.code_block
+ id="scope-fake"
+ class="w-full text-xs mb-4 whitespace-pre-line rounded"
+ phx-no-format
+ ><%= "placeholder\nscopes\nfor\nsync" %>
+
+ Placeholder for any additional instructions here:
+
+ <.code_block
+ id="placeholder-instructions"
+ class="w-full text-xs mb-4 whitespace-pre-line rounded"
+ phx-no-format
+ >placeholder instructions here
+
+
+
+ <.submit_button>
+ Connect Identity Provider
+
"""
diff --git a/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/new.ex b/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/new.ex
index ebd9c4adc..29144fe63 100644
--- a/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/new.ex
+++ b/elixir/apps/web/lib/web/live/settings/identity_providers/openid_connect/new.ex
@@ -3,7 +3,7 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.New do
import Web.Settings.IdentityProviders.OpenIDConnect.Components
alias Domain.Auth
- def mount(_params, _session, socket) do
+ def mount(params, _session, socket) do
id = Ecto.UUID.generate()
account = socket.assigns.account
@@ -17,7 +17,8 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.New do
assign(socket,
id: id,
form: to_form(changeset),
- page_title: "New Identity Provider"
+ page_title: "New Identity Provider",
+ provider: params["provider"]
)
{:ok, socket, temporary_assigns: [form: %Phoenix.HTML.Form{}]}
@@ -41,7 +42,7 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.New do
Add a new OpenID Connect Identity Provider
<:content>
- <.provider_form account={@account} id={@id} form={@form} />
+ <.provider_form account={@account} id={@id} form={@form} show_sync_msg={!!@provider} />
"""
diff --git a/elixir/apps/web/test/web/live/settings/identity_providers/new_test.exs b/elixir/apps/web/test/web/live/settings/identity_providers/new_test.exs
index ca24ff5ad..3e8ae7366 100644
--- a/elixir/apps/web/test/web/live/settings/identity_providers/new_test.exs
+++ b/elixir/apps/web/test/web/live/settings/identity_providers/new_test.exs
@@ -44,8 +44,6 @@ defmodule Web.Live.Settings.IdentityProviders.NewTest do
assert has_element?(lv, "#idp-option-google_workspace")
assert html =~ "Google Workspace"
- assert html =~ "Feature available on a higher pricing plan"
- assert html =~ "UPGRADE TO UNLOCK"
assert has_element?(lv, "#idp-option-microsoft_entra")
assert html =~ "Microsoft Entra"
@@ -56,4 +54,53 @@ defmodule Web.Live.Settings.IdentityProviders.NewTest do
assert has_element?(lv, "#idp-option-openid_connect")
assert html =~ "OpenID Connect"
end
+
+ test "next step for non-idp-sync plans is OIDC form", %{
+ account: account,
+ identity: identity,
+ conn: conn
+ } do
+ {:ok, lv, _html} =
+ conn
+ |> authorize_conn(identity)
+ |> live(~p"/#{account}/settings/identity_providers/new")
+
+ lv
+ |> element("#idp-option-google_workspace")
+ |> render_click()
+
+ assert_redirect(
+ lv,
+ ~p"/#{account}/settings/identity_providers/openid_connect/new?provider=google_workspace"
+ )
+ end
+
+ test "next step for idp-sync plans is to custom adapter form", %{
+ account: account,
+ identity: identity,
+ conn: conn
+ } do
+ Domain.Config.feature_flag_override(:idp_sync, true)
+
+ {:ok, account} =
+ Domain.Accounts.update_account(account, %{
+ features: %{
+ idp_sync: true
+ }
+ })
+
+ {:ok, lv, _html} =
+ conn
+ |> authorize_conn(identity)
+ |> live(~p"/#{account}/settings/identity_providers/new")
+
+ lv
+ |> element("#idp-option-google_workspace")
+ |> render_click()
+
+ assert_redirect(
+ lv,
+ ~p"/#{account}/settings/identity_providers/google_workspace/new"
+ )
+ end
end
diff --git a/elixir/apps/web/test/web/live/settings/identity_providers/openid_connect/new_test.exs b/elixir/apps/web/test/web/live/settings/identity_providers/openid_connect/new_test.exs
index e7fb4a7fb..6f94677a1 100644
--- a/elixir/apps/web/test/web/live/settings/identity_providers/openid_connect/new_test.exs
+++ b/elixir/apps/web/test/web/live/settings/identity_providers/openid_connect/new_test.exs
@@ -35,7 +35,7 @@ defmodule Web.Live.Settings.IdentityProviders.OpenIDConnect.NewTest do
identity: identity,
conn: conn
} do
- {:ok, lv, _html} =
+ {:ok, lv, html} =
conn
|> authorize_conn(identity)
|> live(~p"/#{account}/settings/identity_providers/openid_connect/new")
@@ -51,6 +51,36 @@ defmodule Web.Live.Settings.IdentityProviders.OpenIDConnect.NewTest do
"provider[adapter_config][scope]",
"provider[name]"
]
+
+ refute html =~ "Enable Directory Sync"
+ end
+
+ test "renders provider creation form with blurred sync step", %{
+ account: account,
+ identity: identity,
+ conn: conn
+ } do
+ {:ok, lv, html} =
+ conn
+ |> authorize_conn(identity)
+ |> live(
+ ~p"/#{account}/settings/identity_providers/openid_connect/new?provider=google_workspace"
+ )
+
+ form = form(lv, "form")
+
+ assert find_inputs(form) == [
+ "provider[adapter_config][_persistent_id]",
+ "provider[adapter_config][client_id]",
+ "provider[adapter_config][client_secret]",
+ "provider[adapter_config][discovery_document_uri]",
+ "provider[adapter_config][response_type]",
+ "provider[adapter_config][scope]",
+ "provider[name]"
+ ]
+
+ assert html =~ "Enable Directory Sync"
+ assert html =~ "UPGRADE TO UNLOCK"
end
test "creates a new provider on valid attrs", %{