feat: add LDAP authentication settings and toggle

Add an admin-only LDAP configuration UI with an enable toggle and full
sign-in integration.

Backend:
- ldapSettings model + migration (single-row config)
- GET/PUT/test routes under /ldap (admin-gated; bind password masked)
- shared ldapClient with RFC 4515 filter escaping and empty-password guard
- signin tries local auth first, then LDAP when enabled (find-or-create
  local user) so the bootstrap admin is never locked out

Frontend:
- LDAP settings page (Switch + form + test connection) under /admin/ldap
- AdminNav tabs between user management and LDAP
- ldapControl util, types, and Ldap i18n namespace for all 6 locales

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
LittleYellow
2026-06-26 07:20:08 +08:00
parent 02fa631f02
commit 1c977f9266
25 changed files with 992 additions and 19 deletions

View File

@@ -0,0 +1,49 @@
function defineLdapSetting(sequelize, DataTypes) {
const LdapSetting = sequelize.define('LdapSetting', {
enabled: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
url: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
},
bindDn: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
},
bindCredentials: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
},
searchBase: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
},
// {{username}} is replaced with the value typed in the sign-in form.
searchFilter: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: '(mail={{username}})',
},
emailAttribute: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'mail',
},
usernameAttribute: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'cn',
},
});
return LdapSetting;
}
export default defineLdapSetting;