fix(portal): trigger email for Okta 4xx errors (#10578)

When Okta returned a 4xx status code from the API, we had updated error
handler to grab the errors from body or headers and return these.

However, the caller was expecting an explicit empty string for 401 and
403 errors in order to trigger the email send behavior.

Since that wasn't being matched, we were logging the error internally
only, and continuing to retry the sync indefinitely without sending the
user an email.


Fixes #8744 
Fixes #9825
This commit is contained in:
Jamil
2025-10-16 08:10:04 -07:00
committed by GitHub
parent e81b4dbdac
commit 4d43d2cb77
2 changed files with 56 additions and 7 deletions

View File

@@ -44,15 +44,15 @@ defmodule Domain.Auth.Adapters.Okta.Jobs.SyncDirectory do
message = "#{error_code} => #{error_summary}"
{:error, message, "Okta API returned #{status}: #{message}"}
# TODO: Okta API client needs to be updated to pull message from header
{:error, {401, ""}} ->
{:error, {401, error_map}} ->
user_message = inspect(error_map, pretty: true)
message = "401 - Unauthorized"
{:error, message, message}
{:error, user_message, message}
# TODO: Okta API client needs to be updated to pull message from header
{:error, {403, ""}} ->
{:error, {403, error_map}} ->
user_message = inspect(error_map, pretty: true)
message = "403 - Forbidden"
{:error, message, message}
{:error, user_message, message}
{:error, :retry_later} ->
message = "Okta API is temporarily unavailable"

View File

@@ -941,7 +941,7 @@ defmodule Domain.Auth.Adapters.Okta.Jobs.SyncDirectoryTest do
cancel_bypass_expectations_check(bypass)
end
test "sends email on failed directory sync", %{
test "sends email on failed directory sync when errors are in body", %{
account: account,
provider: provider,
bypass: bypass
@@ -986,5 +986,54 @@ defmodule Domain.Auth.Adapters.Okta.Jobs.SyncDirectoryTest do
cancel_bypass_expectations_check(bypass)
end
test "sends email on failed directory sync when errors are in header", %{
account: account,
provider: provider,
bypass: bypass
} do
actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
_identity = Fixtures.Auth.create_identity(account: account, actor: actor)
# Okta returns 401 with error info in www-authenticate header
www_authenticate_header =
"Bearer authorization_uri=\"http://example.okta.com/oauth2/v1/authorize\", " <>
"realm=\"http://example.okta.com\", " <>
"scope=\"okta.groups.read\", " <>
"error=\"invalid_token\", " <>
"error_description=\"The token has expired.\", " <>
"resource=\"/api/v1/groups\""
for path <- [
"api/v1/users",
"api/v1/groups"
] do
Bypass.stub(bypass, "GET", path, fn conn ->
conn
|> Plug.Conn.put_resp_header("www-authenticate", www_authenticate_header)
|> Plug.Conn.send_resp(401, "")
end)
end
{:ok, pid} = Task.Supervisor.start_link()
provider
|> Ecto.Changeset.change(last_syncs_failed: 9)
|> Repo.update!()
assert execute(%{task_supervisor: pid}) == :ok
assert_email_sent(fn email ->
assert email.subject == "Firezone Identity Provider Sync Error"
assert email.text_body =~ "failed to sync 10 time(s)"
end)
{:ok, pid} = Task.Supervisor.start_link()
assert execute(%{task_supervisor: pid}) == :ok
refute_email_sent()
cancel_bypass_expectations_check(bypass)
end
end
end