The monolithic tab page competed with the settings rail as a second navigation system, and its Integrations tab was a dumping ground. Each section is now its own routed rail page (ServiceNow, Zabbix Supplies, Dell Warranty, Collector PC Types, Branding, Floor Map, Printing and Labels, Email/SMTP, Audit, Authentication, Asset Identifiers, Global Search), thin over a shared useSystemSettings composable, grouped logically in the rail with system groups clustered last. Old /settings/system?tab= URLs redirect to the right page. Also fixes the post-login redirect: the auth guard now remembers the intended destination and Login returns there (same-site paths only). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
164 lines
5.6 KiB
Vue
164 lines
5.6 KiB
Vue
<template>
|
|
<div>
|
|
<div class="page-header">
|
|
<h2>Authentication</h2>
|
|
</div>
|
|
|
|
<div class="section-card">
|
|
<div class="setting-group">
|
|
<h3>SAML Single Sign-On</h3>
|
|
<p class="setting-description">
|
|
Enable SAML SSO for enterprise authentication. Users can sign in using your organization's
|
|
identity provider (Azure AD, Okta, etc.). Local login can remain enabled as a fallback.
|
|
</p>
|
|
|
|
<div class="setting-row">
|
|
<label class="toggle-label">
|
|
<span>Enable SAML SSO</span>
|
|
<button
|
|
class="toggle-btn"
|
|
:class="{ active: settings.saml_enabled }"
|
|
@click="toggleSetting('saml_enabled')"
|
|
:disabled="saving"
|
|
>
|
|
<span class="toggle-slider"></span>
|
|
</button>
|
|
</label>
|
|
</div>
|
|
|
|
<template v-if="settings.saml_enabled">
|
|
<div class="setting-row">
|
|
<label>
|
|
<span>Identity Provider Metadata URL</span>
|
|
<input
|
|
type="url"
|
|
v-model="settings.saml_idp_metadata_url"
|
|
placeholder="https://login.microsoftonline.com/.../federationmetadata.xml"
|
|
@blur="saveSetting('saml_idp_metadata_url', settings.saml_idp_metadata_url)"
|
|
:disabled="saving"
|
|
>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="setting-row">
|
|
<label>
|
|
<span>Service Provider Entity ID</span>
|
|
<input
|
|
type="text"
|
|
v-model="settings.saml_entity_id"
|
|
placeholder="https://shopdb.example.com"
|
|
@blur="saveSetting('saml_entity_id', settings.saml_entity_id)"
|
|
:disabled="saving"
|
|
>
|
|
<small class="input-hint">Unique identifier for this application</small>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="setting-row">
|
|
<label>
|
|
<span>Assertion Consumer Service URL</span>
|
|
<input
|
|
type="url"
|
|
v-model="settings.saml_acs_url"
|
|
placeholder="https://shopdb.example.com/api/auth/saml/acs"
|
|
@blur="saveSetting('saml_acs_url', settings.saml_acs_url)"
|
|
:disabled="saving"
|
|
>
|
|
<small class="input-hint">URL where SAML responses are sent</small>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="setting-row">
|
|
<label>
|
|
<span>Admin Group Name</span>
|
|
<input
|
|
type="text"
|
|
v-model="settings.saml_admin_group"
|
|
placeholder="ShopDB-Admins"
|
|
@blur="saveSetting('saml_admin_group', settings.saml_admin_group)"
|
|
:disabled="saving"
|
|
>
|
|
<small class="input-hint">SAML group that grants admin role (leave empty to manage manually)</small>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="setting-row">
|
|
<label class="toggle-label">
|
|
<span>Allow Local Login</span>
|
|
<button
|
|
class="toggle-btn"
|
|
:class="{ active: settings.saml_allow_local_login }"
|
|
@click="toggleSetting('saml_allow_local_login')"
|
|
:disabled="saving"
|
|
>
|
|
<span class="toggle-slider"></span>
|
|
</button>
|
|
</label>
|
|
<small class="input-hint toggle-hint">Keep enabled for admin fallback access</small>
|
|
</div>
|
|
|
|
<div class="setting-row">
|
|
<label class="toggle-label">
|
|
<span>Auto-Create Users</span>
|
|
<button
|
|
class="toggle-btn"
|
|
:class="{ active: settings.saml_auto_create_users }"
|
|
@click="toggleSetting('saml_auto_create_users')"
|
|
:disabled="saving"
|
|
>
|
|
<span class="toggle-slider"></span>
|
|
</button>
|
|
</label>
|
|
<small class="input-hint toggle-hint">Automatically create user accounts on first SAML login</small>
|
|
</div>
|
|
|
|
<div class="status-indicator">
|
|
<span class="status-dot" :class="samlStatus"></span>
|
|
<span>{{ samlMessage }}</span>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
|
|
<div class="setting-group">
|
|
<h3>User Management</h3>
|
|
<p class="setting-description">
|
|
Manage local user accounts and roles. Local accounts work alongside SAML when both are enabled.
|
|
</p>
|
|
|
|
<router-link to="/settings/users" class="view-logs-link">
|
|
Manage Users →
|
|
</router-link>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="error" class="error-message">{{ error }}</div>
|
|
<div v-if="success" class="settings-success">{{ success }}</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { onMounted, computed } from 'vue'
|
|
import { useSystemSettings } from '../../composables/systemSettings'
|
|
|
|
const {
|
|
settings, saving, error, success,
|
|
loadSettings, saveSetting, toggleSetting,
|
|
} = useSystemSettings()
|
|
|
|
// Per-page connection status (stays with the page, not the composable).
|
|
const samlStatus = computed(() => {
|
|
if (!settings.saml_enabled) return 'inactive'
|
|
if (!settings.saml_idp_metadata_url || !settings.saml_entity_id) return 'warning'
|
|
return 'pending'
|
|
})
|
|
|
|
const samlMessage = computed(() => {
|
|
if (!settings.saml_enabled) return 'Disabled - using local authentication only'
|
|
if (!settings.saml_idp_metadata_url) return 'IdP metadata URL not configured'
|
|
if (!settings.saml_entity_id) return 'Entity ID not configured'
|
|
return 'Configured - SAML login available'
|
|
})
|
|
|
|
onMounted(loadSettings)
|
|
</script>
|