mirror of
https://github.com/czhu12/canine.git
synced 2025-12-30 07:39:43 -06:00
ldap test connection button
This commit is contained in:
@@ -60,6 +60,24 @@ module Accounts
|
||||
end
|
||||
end
|
||||
|
||||
def test_connection
|
||||
ldap_configuration = LDAPConfiguration.new(ldap_configuration_params)
|
||||
result = LDAP::Authenticator.new(ldap_configuration).test_connection
|
||||
|
||||
if result.success?
|
||||
render turbo_stream: turbo_stream.replace(
|
||||
"ldap_test_connection_result",
|
||||
partial: "accounts/sso_providers/ldap/connection_success"
|
||||
)
|
||||
else
|
||||
render turbo_stream: turbo_stream.replace(
|
||||
"ldap_test_connection_result",
|
||||
partial: "accounts/sso_providers/ldap/connection_failed",
|
||||
locals: { error_message: result.error_message }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sso_provider_params
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["button", "result"]
|
||||
|
||||
async test(event) {
|
||||
debugger
|
||||
event.preventDefault()
|
||||
|
||||
const form = this.element.closest("form")
|
||||
const formData = new FormData(form)
|
||||
|
||||
// Clear previous result
|
||||
this.resultTarget.innerHTML = ""
|
||||
|
||||
// Update button to show loading state
|
||||
const button = this.buttonTarget
|
||||
const originalContent = button.innerHTML
|
||||
button.disabled = true
|
||||
button.innerHTML = '<span class="loading loading-spinner loading-xs"></span> Testing...'
|
||||
|
||||
try {
|
||||
const response = await fetch("/accounts/sso_provider/test_connection", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-CSRF-Token": document.querySelector('meta[name="csrf-token"]').content,
|
||||
"Accept": "text/vnd.turbo-stream.html"
|
||||
},
|
||||
body: formData
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
const html = await response.text()
|
||||
Turbo.renderStreamMessage(html)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("LDAP test connection failed:", error)
|
||||
} finally {
|
||||
// Always re-enable the button so it can be clicked again
|
||||
button.disabled = false
|
||||
button.innerHTML = originalContent
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,33 @@ module LDAP
|
||||
|
||||
# Public API
|
||||
# ----------
|
||||
# call(username:, password:) -> Result
|
||||
# test_connection -> Result (tests bind credentials only)
|
||||
# call(username:, password:) -> Result (full authentication)
|
||||
#
|
||||
def test_connection
|
||||
# Validate required configuration
|
||||
if config.host.blank?
|
||||
return Result.new(success?: false, error_message: "Host is required")
|
||||
end
|
||||
|
||||
if config.bind_dn.blank? && !config.allow_anonymous_reads?
|
||||
return Result.new(success?: false, error_message: "Bind DN and password are required when anonymous reads are disabled")
|
||||
end
|
||||
|
||||
reader_ldap = build_reader_connection
|
||||
|
||||
if reader_ldap.bind
|
||||
Result.new(success?: true, error_message: nil)
|
||||
else
|
||||
msg = "LDAP bind failed: #{reader_ldap.get_operation_result.message}"
|
||||
@logger.warn msg
|
||||
Result.new(success?: false, error_message: msg)
|
||||
end
|
||||
rescue => e
|
||||
@logger.error "LDAP test connection: unexpected error - #{e.class}: #{e.message}"
|
||||
Result.new(success?: false, error_message: e.message)
|
||||
end
|
||||
|
||||
def call(username:, password:, fetch_groups:)
|
||||
# 1) Bind as reader (service account or anonymous)
|
||||
reader_ldap = build_reader_connection
|
||||
@@ -54,8 +79,8 @@ module LDAP
|
||||
end
|
||||
|
||||
# 4) Successful LDAP auth → map attributes, fetch groups
|
||||
email = resolve_email(entry, username)
|
||||
name = resolve_name(entry, username)
|
||||
email = resolve_email(entry, username)
|
||||
name = resolve_name(entry, username)
|
||||
if fetch_groups
|
||||
groups = fetch_group_membership(entry)
|
||||
else
|
||||
@@ -103,6 +128,7 @@ module LDAP
|
||||
# No way to bind safely
|
||||
# Let caller see failure via bind result
|
||||
logger.info "LDAP: no reader credentials and anonymous reads disabled"
|
||||
raise "LDAP: no reader credentials and anonymous reads disabled"
|
||||
end
|
||||
|
||||
Net::LDAP.new(options)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<%= turbo_frame_tag "ldap_test_connection_result", class: "block mt-3", data: { ldap_test_connection_target: "result" } do %>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex items-center gap-2 text-error">
|
||||
<iconify-icon icon="lucide:x-circle" height="16"></iconify-icon>
|
||||
<span>Connection failed</span>
|
||||
</div>
|
||||
<% if local_assigns[:error_message].present? %>
|
||||
<span class="text-sm text-base-content/70"><%= error_message %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -0,0 +1,6 @@
|
||||
<%= turbo_frame_tag "ldap_test_connection_result", class: "block mt-3", data: { ldap_test_connection_target: "result" } do %>
|
||||
<div class="flex items-center gap-2 text-success">
|
||||
<iconify-icon icon="lucide:check-circle" height="16"></iconify-icon>
|
||||
<span>Connection successful!</span>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -107,4 +107,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<div class="mt-6 mb-4" data-controller="ldap-test-connection">
|
||||
<button type="button"
|
||||
class="btn btn-outline btn-sm"
|
||||
data-action="click->ldap-test-connection#test"
|
||||
data-ldap-test-connection-target="button">
|
||||
<iconify-icon icon="lucide:plug" height="16"></iconify-icon>
|
||||
Test Connection
|
||||
</button>
|
||||
<%= turbo_frame_tag "ldap_test_connection_result", class: "block mt-3", data: { ldap_test_connection_target: "result" } do %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -16,7 +16,9 @@ Rails.application.routes.draw do
|
||||
resources :accounts, only: [ :create ] do
|
||||
collection do
|
||||
resources :account_users, only: %i[create index destroy], module: :accounts
|
||||
resource :sso_provider, only: %i[show new create edit update destroy], module: :accounts
|
||||
resource :sso_provider, only: %i[show new create edit update destroy], module: :accounts do
|
||||
post :test_connection
|
||||
end
|
||||
resources :teams, module: :accounts do
|
||||
resources :team_memberships, only: %i[create destroy], module: :teams
|
||||
resources :team_resources, only: %i[create destroy], module: :teams
|
||||
|
||||
Reference in New Issue
Block a user