LDAP admin GUI + group filter
- LDAP settings configurable from Admin panel (no restart needed) - Required group filter: only users in specified group can login - Supports both memberOf attribute and groupOfNames search - Settings stored in DB (settings table), env vars as fallback - SLDAP supported via ldaps:// URL - Bind password masked in UI
This commit is contained in:
+42
-1
@@ -255,6 +255,26 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="panel-section">
|
||||
<h3>LDAP / SLDAP Authentication</h3>
|
||||
<form @submit.prevent="saveLdapSettings" class="admin-form">
|
||||
<label>Server URL</label>
|
||||
<input v-model="ldapSettings.ldap_url" placeholder="ldap://host:389 or ldaps://host:636" />
|
||||
<label>Bind DN</label>
|
||||
<input v-model="ldapSettings.ldap_bind_dn" placeholder="cn=service,dc=example,dc=com" />
|
||||
<label>Bind Password</label>
|
||||
<input v-model="ldapSettings.ldap_bind_pass" type="password" placeholder="Service account password" />
|
||||
<label>Base DN</label>
|
||||
<input v-model="ldapSettings.ldap_base_dn" placeholder="dc=example,dc=com" />
|
||||
<label>User Filter</label>
|
||||
<input v-model="ldapSettings.ldap_user_filter" placeholder="(&(objectClass=inetOrgPerson)(uid=%s))" />
|
||||
<label>Required Group (DN or CN)</label>
|
||||
<input v-model="ldapSettings.ldap_group_filter" placeholder="cn=markdownhub-users,ou=groups,dc=..." />
|
||||
<label><input type="checkbox" v-model="ldapSkipTLS" /> Skip TLS verification</label>
|
||||
<button type="submit">Save LDAP Settings</button>
|
||||
</form>
|
||||
<p v-if="ldapMsg" class="admin-msg">{{ ldapMsg }}</p>
|
||||
</div>
|
||||
</main>
|
||||
<!-- About -->
|
||||
<main class="panel" v-if="view === 'about'" style="text-align:center;padding-top:80px">
|
||||
@@ -380,6 +400,9 @@ const newRemote = ref({ name: '', url: '' })
|
||||
const users = ref([])
|
||||
const newUser = ref({ username: '', email: '', password: '', isAdmin: false })
|
||||
const adminMsg = ref('')
|
||||
const ldapSettings = ref({ ldap_url: '', ldap_bind_dn: '', ldap_bind_pass: '', ldap_base_dn: '', ldap_user_filter: '', ldap_group_filter: '' })
|
||||
const ldapSkipTLS = ref(false)
|
||||
const ldapMsg = ref('')
|
||||
|
||||
const rendered = computed(() => renderMarkdown(content.value))
|
||||
|
||||
@@ -404,7 +427,7 @@ async function login() {
|
||||
loadShared()
|
||||
loadRemotes()
|
||||
syncPending()
|
||||
if (isAdmin.value) loadUsers()
|
||||
if (isAdmin.value) { loadUsers(); loadLdapSettings() }
|
||||
// Sync pending changes when coming back online
|
||||
window.addEventListener('online', syncPending)
|
||||
} catch (e) {
|
||||
@@ -777,6 +800,24 @@ async function adminCreateUser() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadLdapSettings() {
|
||||
try {
|
||||
ldapSettings.value = await api('/api/admin/settings/get', {})
|
||||
ldapSkipTLS.value = ldapSettings.value.ldap_skip_tls === 'true'
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function saveLdapSettings() {
|
||||
const data = { ...ldapSettings.value, ldap_skip_tls: ldapSkipTLS.value ? 'true' : 'false' }
|
||||
try {
|
||||
await api('/api/admin/settings/save', data)
|
||||
ldapMsg.value = 'LDAP settings saved'
|
||||
toast('LDAP settings saved', 'success')
|
||||
} catch {
|
||||
ldapMsg.value = 'Failed to save'
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(d) {
|
||||
if (!d) return ''
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user