Skip to content

Commit 027dba9

Browse files
feat(rbac): enable okta login when creating integration (#416)
## 📝 Description renderedtext/tasks#8169 ## ✅ Checklist - [x] I have tested this change - [ ] This change requires documentation update
1 parent 11cd360 commit 027dba9

File tree

6 files changed

+339
-39
lines changed

6 files changed

+339
-39
lines changed

ee/rbac/lib/rbac/api/organization.ex

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ defmodule Rbac.Api.Organization do
44

55
def find_by_username(username) do
66
req = %Organization.DescribeRequest{org_username: username}
7+
describe_organization(req)
8+
end
9+
10+
def find_by_id(org_id) do
11+
req = %Organization.DescribeRequest{org_id: org_id}
12+
describe_organization(req)
13+
end
14+
15+
defp describe_organization(req) do
716
{:ok, channel} = GRPC.Stub.connect(Application.fetch_env!(:rbac, :organization_grpc_endpoint))
817

918
Logger.info("Sending Organization describe request: #{inspect(req)}")
@@ -20,4 +29,20 @@ defmodule Rbac.Api.Organization do
2029
{:error, :not_found}
2130
end
2231
end
32+
33+
def update(organization) do
34+
req = %Organization.UpdateRequest{organization: organization}
35+
{:ok, channel} = GRPC.Stub.connect(Application.fetch_env!(:rbac, :organization_grpc_endpoint))
36+
37+
Logger.info("Sending Organization update request: #{inspect(req)}")
38+
39+
grpc_result = Organization.OrganizationService.Stub.update(channel, req, timeout: 30_000)
40+
41+
Logger.info("Received Organization update response: #{inspect(grpc_result)}")
42+
43+
case grpc_result do
44+
{:ok, res} -> {:ok, res.organization}
45+
{:error, error} -> {:error, error}
46+
end
47+
end
2348
end

ee/rbac/lib/rbac/okta/integrations.ex

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ defmodule Rbac.Okta.Integration do
44
"""
55

66
require Ecto.Query
7+
require Logger
8+
79
alias Ecto.Query
810
alias Rbac.Repo
911
alias Rbac.Okta.Saml.Certificate
@@ -21,23 +23,82 @@ defmodule Rbac.Okta.Integration do
2123
jit_provisioning_enabled,
2224
idempotency_token \\ Ecto.UUID.generate()
2325
) do
24-
with {:ok, fingerprint} <- Certificate.fingerprint(certificate),
25-
{:ok, integration} <-
26-
Rbac.Repo.OktaIntegration.insert_or_update(
27-
org_id: org_id,
28-
creator_id: creator_id,
29-
sso_url: sso_url,
30-
saml_issuer: saml_issuer,
31-
saml_certificate_fingerprint: Base.encode64(fingerprint),
32-
jit_provisioning_enabled: jit_provisioning_enabled,
33-
idempotency_token: idempotency_token
34-
) do
35-
{:ok, integration}
26+
Ecto.Multi.new()
27+
|> Ecto.Multi.run(:fingerprint, fn _repo, _changes ->
28+
Certificate.fingerprint(certificate)
29+
end)
30+
|> Ecto.Multi.run(:integration, fn _repo, %{fingerprint: fingerprint} ->
31+
Rbac.Repo.OktaIntegration.insert_or_update(
32+
org_id: org_id,
33+
creator_id: creator_id,
34+
sso_url: sso_url,
35+
saml_issuer: saml_issuer,
36+
saml_certificate_fingerprint: Base.encode64(fingerprint),
37+
jit_provisioning_enabled: jit_provisioning_enabled,
38+
idempotency_token: idempotency_token
39+
)
40+
end)
41+
|> Ecto.Multi.run(:allowed_id_providers, fn _repo, _changes ->
42+
add_okta_to_allowed_id_providers(org_id)
43+
end)
44+
|> Rbac.Repo.transaction()
45+
|> case do
46+
{:ok, %{integration: integration}} ->
47+
{:ok, integration}
48+
49+
{:error, :fingerprint, reason, _changes} ->
50+
Logger.error("Failed to decode certificate for org #{org_id}: #{inspect(reason)}.")
51+
{:error, :cert_decode_error}
52+
53+
{:error, :integration, reason, _changes} ->
54+
Logger.error(
55+
"Failed to create/update Okta integration for org #{org_id}: #{inspect(reason)}"
56+
)
57+
58+
{:error, {:integration_failed, reason}}
59+
60+
{:error, :allowed_id_providers, reason, _changes} ->
61+
Logger.error(
62+
"Failed to add Okta to allowed ID providers for org #{org_id}: #{inspect(reason)}"
63+
)
64+
65+
{:error, {:allowed_id_providers_failed, reason}}
66+
67+
{:error, operation, reason, _changes} ->
68+
Logger.error(
69+
"Unknown operation #{inspect(operation)} failed for org #{org_id}: #{inspect(reason)}"
70+
)
71+
72+
{:error, reason}
73+
end
74+
end
75+
76+
defp update_id_providers(org_id, operation, action) do
77+
with {:ok, org} <- Rbac.Api.Organization.find_by_id(org_id),
78+
updated_providers <- operation.(org.allowed_id_providers || []),
79+
updated_org <- Map.put(org, :allowed_id_providers, updated_providers),
80+
{:ok, updated} <- Rbac.Api.Organization.update(updated_org) do
81+
{:ok, updated}
3682
else
37-
e -> e
83+
{:error, :not_found} ->
84+
Logger.error("Failed to #{action} okta provider: Org #{org_id} not found")
85+
{:error, :organization_not_found}
86+
87+
{:error, reason} ->
88+
Logger.error("Failed to #{action} okta provider for org #{org_id}: #{inspect(reason)}")
89+
90+
{:error, :update_failed}
3891
end
3992
end
4093

94+
defp add_okta_to_allowed_id_providers(org_id) do
95+
update_id_providers(org_id, &Enum.uniq(&1 ++ ["okta"]), "add")
96+
end
97+
98+
defp remove_okta_from_allowed_id_providers(org_id) do
99+
update_id_providers(org_id, &Enum.reject(&1, fn provider -> provider == "okta" end), "remove")
100+
end
101+
41102
def generate_scim_token(integration) do
42103
token = Rbac.Okta.Scim.Token.generate()
43104
token_hash = Rbac.Okta.Scim.Token.hash(token)
@@ -96,10 +157,13 @@ defmodule Rbac.Okta.Integration do
96157
Rbac.RoleManagement.retract_roles(rbi, :okta)
97158
{:ok, :retracted_roles}
98159
end)
99-
|> Ecto.Multi.run(:delete_okta_users, fn _repo, _cahnges ->
160+
|> Ecto.Multi.run(:delete_okta_users, fn _repo, _changes ->
100161
OktaUser.delete_all(id)
101162
{:ok, :okta_users_deleted}
102163
end)
164+
|> Ecto.Multi.run(:remove_okta_from_allowed_id_providers, fn _repo, _changes ->
165+
remove_okta_from_allowed_id_providers(integration.org_id)
166+
end)
103167
|> Ecto.Multi.delete(:delete_okta_integration, integration)
104168
|> Rbac.Repo.transaction(timeout: 60_000)
105169

0 commit comments

Comments
 (0)