Skip to content

Commit d90c44e

Browse files
committed
fix race condition in JIT provisioning, use route helper for SSO form
- Add RetryProvisioning to handle concurrent first logins: when RecordNotUnique is raised on save, retry call once so find_or_adopt_or_build finds the now-persisted record - Use omniauth_authorize_path helper instead of hardcoded /admin/auth/oidc - Simplify resolve_admin_user_class to use constantize
1 parent c52cc1e commit d90c44e

3 files changed

Lines changed: 15 additions & 4 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div id="login">
22
<h2><%= active_admin_application.site_title(self) %></h2>
33

4-
<%= form_tag "/admin/auth/oidc", method: :post, data: { turbo: false } do %>
4+
<%= form_tag omniauth_authorize_path(resource_name, :oidc), method: :post, data: { turbo: false } do %>
55
<%= submit_tag ActiveAdmin::Oidc.config.login_button_label %>
66
<% end %>
77
</div>

lib/activeadmin-oidc.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module Oidc
2525
class Error < StandardError; end
2626
class ConfigurationError < Error; end
2727
class ProvisioningError < Error; end
28+
class RetryProvisioning < Error; end
2829

2930
class << self
3031
def config

lib/activeadmin/oidc/user_provisioner.rb

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ def call
4242

4343
save!(admin_user)
4444
admin_user
45+
rescue RetryProvisioning
46+
# Concurrent JIT provisioning: another thread inserted first.
47+
# Re-run once — find_or_adopt_or_build will now find the record.
48+
retry
4549
end
4650

4751
private
@@ -51,8 +55,7 @@ def model
5155
end
5256

5357
def resolve_admin_user_class
54-
value = @config.admin_user_class
55-
value.is_a?(Class) ? value : Object.const_get(value)
58+
@config.admin_user_class.is_a?(Class) ? @config.admin_user_class : @config.admin_user_class.constantize
5659
end
5760

5861
def validate_claims!
@@ -101,7 +104,14 @@ def sanitized_raw_info
101104

102105
def save!(admin_user)
103106
admin_user.save!
104-
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e
107+
rescue ActiveRecord::RecordNotUnique
108+
raise ProvisioningError, denial_message if @retried
109+
110+
# Concurrent JIT provisioning race: the other thread won the
111+
# insert. Re-run call once to find the now-persisted record.
112+
@retried = true
113+
raise RetryProvisioning
114+
rescue ActiveRecord::RecordInvalid => e
105115
raise ProvisioningError, e.message
106116
end
107117

0 commit comments

Comments
 (0)