refactor: config + lldaplib 收敛到 LLDAP 形态(读只读、删 OpenLDAP 写路径与密码包)
- config 重写:删 user-ou/inactive-ou/group-root-* / group-object-class / group-member-attr / initial-password;新增 lldap 写通道 + webhook + confirm-base-url + 两套 schedule + guard - ldaplib 收拢为只读:属性常量/DN 归入 attrs.go;删 ops.go 写路径与 internal/password - config.example.yml 重写成 LLDAP 形态 - 组命名修订(呼应 AGENTS.md 约束12):用部门稳定索引 cn=<dept_id> 做组身份, mirror_departments 增 group_id 列并跨快照保留,可读中文名只走 DB 展示
This commit is contained in:
+10
-23
@@ -1,5 +1,7 @@
|
||||
package ldaplib
|
||||
|
||||
// LLDAP 的 LDAP 读通道:连接、绑定、搜索。刻意只读,写全走 lldapgql。
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
@@ -12,19 +14,16 @@ import (
|
||||
"idsync/internal/config"
|
||||
)
|
||||
|
||||
// Client 封装与 OpenLDAP 的连接。它刻意不使用连接池:同步任务的并发很低,
|
||||
// 且池化连接在长时间空闲后容易变成半开状态,反而制造难以诊断的失败。
|
||||
// Client 封装与 LLDAP 的 LDAP 连接。不使用连接池:同步任务的并发很低,
|
||||
// 每次操作新建连接、用完即关,代价是一个 TCP 往返,换取确定性。
|
||||
type Client struct {
|
||||
cfg config.Ldap
|
||||
log *slog.Logger
|
||||
tlsConf *tls.Config
|
||||
dialOpts []ldap.DialOpt
|
||||
// group 是分组条目的形态,取自配置,必须与 Authelia 的 groups_filter 匹配。
|
||||
group GroupSchema
|
||||
}
|
||||
|
||||
// NewClient 构造 LDAP 客户端,并解析出拨号参数。
|
||||
// NewClient 构造 LDAP 读客户端并解析拨号参数。
|
||||
func NewClient(cfg config.Ldap, log *slog.Logger) (*Client, error) {
|
||||
if cfg.URL == "" {
|
||||
return nil, fmt.Errorf("ldap.url 未配置")
|
||||
@@ -43,25 +42,13 @@ func NewClient(cfg config.Ldap, log *slog.Logger) (*Client, error) {
|
||||
dialOpts = append(dialOpts, ldap.DialWithTLSConfig(tlsConf))
|
||||
}
|
||||
|
||||
schema := GroupSchema{
|
||||
ObjectClass: cfg.GroupObjectClass,
|
||||
MemberAttr: cfg.GroupMemberAttr,
|
||||
}
|
||||
if schema.ObjectClass == "" {
|
||||
schema.ObjectClass = "groupOfUniqueNames"
|
||||
}
|
||||
if schema.MemberAttr == "" {
|
||||
schema.MemberAttr = "uniqueMember"
|
||||
}
|
||||
|
||||
return &Client{cfg: cfg, log: log, tlsConf: tlsConf, dialOpts: dialOpts, group: schema}, nil
|
||||
return &Client{cfg: cfg, log: log, tlsConf: tlsConf, dialOpts: dialOpts}, nil
|
||||
}
|
||||
|
||||
// Conn 是一次性的 LDAP 会话。务必用 defer c.Close()。
|
||||
type Conn struct {
|
||||
conn *ldap.Conn
|
||||
cfg config.Ldap
|
||||
group GroupSchema
|
||||
conn *ldap.Conn
|
||||
cfg config.Ldap
|
||||
}
|
||||
|
||||
// Close 释放连接。
|
||||
@@ -87,10 +74,10 @@ func (c *Client) Dial() (*Conn, error) {
|
||||
|
||||
if err := conn.Bind(c.cfg.AdminDN, c.cfg.AdminPass); err != nil {
|
||||
_ = conn.Close()
|
||||
return nil, fmt.Errorf("绑定 LDAP 管理员失败 (%s): %w", c.cfg.AdminDN, err)
|
||||
return nil, fmt.Errorf("绑定 LDAP 失败 (%s): %w", c.cfg.AdminDN, err)
|
||||
}
|
||||
|
||||
return &Conn{conn: conn, cfg: c.cfg, group: c.group}, nil
|
||||
return &Conn{conn: conn, cfg: c.cfg}, nil
|
||||
}
|
||||
|
||||
// Ping 验证连通性与凭据,用于健康检查。
|
||||
@@ -132,4 +119,4 @@ func lastIndexByte(s string, b byte) int {
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user